24

私のプロジェクトのいくつかといくつかの本では、内部クラス (匿名かどうか、静的かどうか) を使用しないと言われていました。私の最初の業界プロジェクトでは、それらは「禁止」されていました。EventListenerRunnable

これは本当にベストプラクティスですか?なんで?

(私はそれらをたくさん使っていると言わざるを得ません...)

-- 編集 ---
これらすべての回答で正しい答えを選ぶことはできません: ほとんどすべての回答に正しい部分があります: 私はまだ内部クラスを使用しますが、それらをあまり使用しないようにします!

4

15 に答える 15

32

私の見解では、Java コードの内部クラスの 90% は、単一のクラスに関連付けられているために内部クラスとして「押し込まれた」エンティティーか、Java が Lambda をサポートしていないために存在する匿名の内部クラスのいずれかです。

個人的には、複雑な内部クラスを見るのは好きではありません。それらはソース ファイルを複雑にし、サイズを大きくし、デバッグやプロファイリングなどの点で扱いにくくなります。プロジェクトを多くのパッケージに分割するのが好きです。この場合、ほとんどのエンティティをトップレベル クラスにすることができます。パッケージに制限されています。

これにより、アクションリスナー、偽の「関数型」プログラミングなど、必要な内部クラスが残ります。これらは多くの場合匿名であり、私はファンではありませんが (多くの場合、Lambda を好むでしょう)、私はそれらと一緒に住んでいますが、それらが好きではありません。

私は何年も C# を使っていませんが、ラムダが導入されたときに、内部クラスの普及や C# に相当するものは何でもなくなったのではないかと思っています。

于 2010-02-17T21:24:41.530 に答える
17

清潔さ。コードが論理的な断片に分割されている場合、コードを理解するのは簡単です。すべてが同じファイルにまとめられているわけではありません。

そうは言っても、私は内部クラスの賢明な使用が不適切であるとは考えていません。これらの内部クラスは 1 つの目的のためにのみ存在する場合があるため、それらが使用される唯一のファイルに存在しても問題ありません。しかし、これは私の経験ではあまり起こりません。

于 2010-02-17T21:12:40.363 に答える
6

匿名クラスは、特にスイングでイベントベースのプログラミングを行う場合に使用するのに適しています。

于 2010-02-17T21:12:55.457 に答える
5

はい、内部クラスを禁止することは有用な慣行です。禁止されている場所を見つけることは、そこで働くことを警告する良い方法であり、したがって私の将来の正気を保ちます。:)

gicappa が指摘しているように、匿名の内部クラスは、Java が持つクロージャーに最も近いものであり、動作をメソッドに渡すことが適切な状況での使用に非常に適しています。

于 2010-02-18T11:05:03.563 に答える
4

他の人が言ったように、多くの場合、匿名の内部クラスを使用すると、他の場所でも使用されます...

したがって、内部クラスのコードを多くの場所に簡単に複製できます...非常に単純な内部クラスを使用してコレクションをフィルタリング/ソートし、述語、コンパレータなどを使用している場合、これは問題ではないようです...

ただし、まったく同じことを行う匿名の内部クラスを 3 回使用する場合 (たとえば、コレクションの "" を削除する場合)、実際には Java PermGen で 3 つの新しいクラスを作成していることを知っておく必要があります。

そのため、誰もがどこでも内部クラスを使用すると、アプリケーションの permgen が大きくなる可能性があります。アプリケーションによっては、これが問題になる可能性があります...業界で働いている場合は、最適化する必要があるメモリが限られている組み込みアプリケーションをプログラムすることがあります...

これは、二重中括弧構文 (非静的初期化ブロックを持つ匿名の内部クラス) が時々アンチパターンと見なされる理由でもあることに注意してください。

new ArrayList<String>() {{
     add("java");
     add("jsp");
     add("servlets");
  }}

それらを使用することを禁止する人に尋ねる必要があります... IMHOそれはすべて文脈に依存します...

于 2011-08-16T10:52:09.203 に答える
3

匿名の内部クラスには、「新しい」ステートメントの周りのフィールドと変数を表示できるという利点があります。これにより、非常にクリーンな設計が可能になり、「ラムダステートメントの単純なバージョンを作成するにはどうすればよいか」に対する非常に優れた(ただし少し言葉遣いのある)アプローチになります。

名前付き内部クラスには、名前を付けるという利点があります。名前を付けると、通常の方法で文書化できますが、周囲のクラスに関連付けられます。非常に良い例はBuilderパターンです。このパターンでは、多数のコンストラクターを使用する代わりに、内部クラスが初期化プロセスの状態を提供します。このようなビルダーはクラス間で再利用できないため、ビルダーを親クラスに緊密に結び付けることは完全に理にかなっています。

于 2010-02-18T03:30:51.200 に答える
3

メソッド パラメーターが必要な場合は、慎重に使用することをお勧めします。それに関連するメモリリークが見つかりました。これには、GrizzlyContinuation を使用する HttpServlet が含まれます。
要するに、バグのあるコードは次のとおりです。

public void doGet(HttpServletRequest request, final HttpServletResponse response){
  createSubscription(..., new SubscriptionListener(){
    public void subscriptionCreated(final CallController controller) {
      response.setStatus(200);
      ...
      controller.resume();
    }

    public void subscriptionFailed(){
       ...
     }

    public void subscriptionTimeout(){
      ...
  }});
}

したがって、リスナーはサブスクリプションによって保持されるため、リスナーが必要な場合に備えて HttpServletResponse も保持されます (明らかではありません)。その後、サブスクリプションが削除された場合にのみ HttpServletResponse インスタンスが解放されます。コンストラクターで応答を取得する内部クラスを使用する場合、呼び出しがメモリの解放を再開すると、null に設定できます。

それらを使用しますが、注意してください!

マーティン

于 2011-11-30T22:40:17.850 に答える
3

ここで言及されていない項目の 1 つは、(非静的) 内部クラスがそれを囲むクラスへの参照を保持することです。さらに重要なことに、内部クラスはそれを囲むクラスのプライベート メンバーにアクセスできます。カプセル化を破る可能性があります。

オプションがある場合は、内部クラスを使用しないでください。

于 2012-01-18T17:31:38.170 に答える
2

Wicket などの特定のフレームワークでは、匿名の内部クラスが実際に必要です。

決して言わないのはばかげています。絶対とは絶対言うな!適切な使用例は、多くのクラスが Collection フィールドで直接動作する誰かによって書かれたレガシー コードがあり、何らかの理由でそれらの他のクラスを変更することはできませんが、条件付きで操作を別のクラスにミラーリングする必要がある場合です。コレクション。最も簡単な方法は、匿名の内部クラスを介してこの動作を追加することです。

bagOfStuff = new HashSet(){
  @Override
  public boolean add(Object o) {
    boolean returnValue = super.add(o);
    if(returnValue && o instanceof Job)
    {
      Job job = ((Job)o);
      if(job.fooBar())
         otherBagOfStuff.add(job);
    }
    return returnValue;
  }
}

とはいえ、貧乏人のクロージャーのように間違いなく使用できます。

于 2010-11-01T19:48:17.297 に答える
1

内部クラスは、メソッドのパラメーターとして「動作を渡す」ためによく使用されます。この機能は、クロージャを持つ他の言語によって洗練された方法でサポートされています。内部クラスを使用すると、言語の制限により洗練されていないコード (IMHO) が生成されますが、一般的に内部クラスでイベントやブロックを処理するために便利で広く使用されています。

したがって、内部クラスは非常に便利です。

于 2010-02-17T22:27:06.740 に答える
1

内部クラスは、多重継承をエミュレートしようとする場合に適しています。これは、C++ の内部で発生することと似ています。C++ で多重継承がある場合、メモリ内のオブジェクト レイアウトは、実際には複数のオブジェクト インスタンスの連結です。次に、コンパイラは、メソッドが呼び出されたときに「this」ポインターをどのように調整するかを決定します。Java には多重継承はありませんが、内部クラスを使用して、特定のインスタンスの「ビュー」を別の型の下に提供できます。

ほとんどの場合、単一継承に固執することは可能ですが、場合によっては多重継承が適切なツールであり、そのような場合はインナー クラスを使用します。

これは、多重継承が単一継承よりも複雑であるのと同じように、内部クラスが通常のクラスよりも複雑であることを意味します。多くのプログラマーは、その概念に頭を悩ませています。したがって、「ベスト プラクティス」: 同僚を混乱させるため、内部クラスは避けてください。私の見解では、これは良い議論ではありません。私の職場では、適切と思われる場合は喜んで内部クラスを使用します。

(内部クラスの小さな欠点は、ソース コードに 1 レベルの余分なインデントを追加することです。これは、コードを 79 列以内に収めたい場合に少し面倒です。)

于 2010-02-17T21:22:05.893 に答える
1

匿名の内部クラスは、Runnable、ActionListener などの 1 つのメソッドでインターフェイスを実装する必要がある場合によく使用されます。

匿名内部クラスのもう 1 つの優れたアプライアンスは、あるクラスのサブクラスを作成したくないが、そのメソッドの 1 つ (または 2 つ) をオーバーライドする必要がある場合です。

名前付き内部クラスは、2 つのクラス間で緊密な一貫性を実現したい場合に使用できます。それらは匿名の内部クラスほど有用ではなく、それらを使用することが良い習慣であるかどうかはわかりません。

Java には、ネストされた (または内部静的) クラスもあります。これらは、特別なアクセスを提供したい場合や、標準のパブリックまたはデフォルトのアクセス レベルでは不十分な場合に使用できます。

于 2010-02-17T21:24:48.677 に答える
0

はい、クラスのまとまりを維持しようとしているときにそれらを使用するのは良いことです。クラスは外部クラスのコンテキストの外部からインスタンス化されるべきではなく、コンストラクターをプライベートにすると、非常に優れたまとまりのあるカプセル化が得られます。それらを絶対に使用してはならないという人は、彼らが何について話しているのかわかりません。匿名の内部クラスが得意とするイベント ハンドラーやその他の機能については、特定のクラスにのみ適用される多数のイベント ハンドラーでパッケージの名前空間を乱雑にするよりもはるかに優れています。

于 2010-02-17T21:56:18.050 に答える