インナークラス

Q:とにかく、内部クラスは何に適していますか?

A:内部クラスは他のクラス内にネストします。通常のクラスは、パッケージの直接のメンバーである最上位クラスです。Java 1.1で利用可能になった内部クラスには、次の4つの種類があります。

  • 静的メンバークラス
  • メンバークラス
  • ローカルクラス
  • 匿名クラス

それぞれを順番に見ていきましょう。

簡単に言うと、静的メンバークラスクラスの静的メンバーです。他の静的メソッドと同様に、静的メンバークラスは、親クラスまたは最上位クラスのすべての静的メソッドにアクセスできます。

静的メンバークラスと同様に、メンバークラスクラスのメンバーとして定義されます。静的な種類とは異なり、メンバークラスはインスタンス固有であり、親のthis参照も含め、すべてのメソッドとメンバーにアクセスできます。

ローカルクラスはコードのブロック内で宣言され、他のメソッド変数と同様に、そのブロック内でのみ表示されます。

最後に、匿名クラスは名前のないローカルクラスです。

あなたの特定の質問に答えるために、私はメンバーと匿名の内部クラスに焦点を合わせます。それらはあなたが遭遇して使用する可能性が高いものだからです。私にとって、内部クラスの利点は、オブジェクト指向の利点、組織の利点、およびコールバックの利点の3つのカテゴリに分類できます。

オブジェクト指向の利点

私の謙虚な意見では、内部クラスの最も重要な機能は、通常はオブジェクトに変換されないオブジェクトに物事を変換できることです。これにより、内部クラスがない場合よりも、コードをさらにオブジェクト指向にすることができます。

メンバークラスを見てみましょう。そのインスタンスはその親インスタンスのメンバーであるため、親のすべてのメンバーとメソッドにアクセスできます。一見、これはそれほど多くないように見えるかもしれません。親クラスのメソッド内から、すでにそのようなアクセス権があります。ただし、メンバークラスを使用すると、親からロジックを取り出してオブジェクト化できます。たとえば、ツリークラスには、ツリーの検索またはウォークを実行するメソッドと多くのヘルパーメソッドが含まれる場合があります。オブジェクト指向の観点からは、ツリーはツリーであり、検索アルゴリズムではありません。ただし、検索を実行するには、ツリーのデータ構造に関する深い知識が必要です。

内部クラスを使用すると、そのロジックを削除して独自のクラスに配置できます。そのため、オブジェクト指向の観点から、機能が属していない場所から機能を取り除き、独自のクラスに配置しました。内部クラスを使用することで、検索アルゴリズムをツリーから切り離すことができました。ここで、検索アルゴリズムを変更するには、新しいクラスに切り替えるだけです。先に進むこともできますが、それによって、オブジェクト指向技術によって提供される多くの利点にコードが開かれます。

組織の利点

オブジェクト指向設計はすべての人のものではありませんが、幸いなことに、内部クラスはより多くのものを提供します。組織的な観点から、内部クラスを使用すると、名前空間を使用してパッケージ構造をさらに整理できます。すべてをフラットパッケージにダンプする代わりに、クラスをクラス内にさらにネストすることができます。明示的に、内部クラスがない場合、次の階層構造に制限されていました。

パッケージ1クラス1クラス2 ...クラスn ...パッケージn 

内部クラスを使用すると、次のことができます。

パッケージ1クラス1クラス2クラス1クラス2 ...クラスn 

注意深く使用すると、内部クラスは、クラスにより自然に適合する構造階層を提供できます。

コールバックの利点

内部メンバークラスと匿名クラスはどちらも、コールバックを定義するための便利な方法を提供します。最も明白な例はGUIコードに関連しています。ただし、コールバックのアプリケーションは多くのドメインに拡張できます。

ほとんどのJavaGUIには、actionPerformed()メソッド呼び出しを引き起こす何らかのコンポーネントがあります。残念ながら、ほとんどの開発者はメインウィンドウに実装しているだけActionListenerです。その結果、すべてのコンポーネントが同じactionPerformed()メソッドを共有します。どのコンポーネントがアクションを実行したかを把握するために、通常、actionPerformed()メソッドには巨大で醜いスイッチがあります。

モノリシック実装の例を次に示します。

パブリッククラスSomeGUIはJFrameを拡張し、ActionListener {protected JButtonbutton1;を実装します。保護されたJButtonボタン2; ...保護されたJButtonbuttonN; public void actionPerformed(ActionEvent e){if(e.getSource()== button1){//何かをする} else if(e.getSource()== button2){...画像を取得する

スイッチや大きなif/if elseブロックが表示されるたびに、大きなアラームベルが頭の中で鳴り始めます。一般に、コードの1つのセクションを変更すると、対応するswitchステートメントの変更が必要になる可能性があるため、このような構造はオブジェクト指向設計としては不適切です。内部メンバークラスと匿名クラスを使用すると、切り替えられたactionPerformed()メソッドから離れることができます。

代わりに、ActionListenerリッスンするコンポーネントごとに実装する内部クラスを定義できます。その結果、多くの内部クラスが発生する可能性があります。ただし、大きなswitchステートメントを回避し、アクションロジックをカプセル化するという追加のボーナスを得ることができます。さらに、そのアプローチはパフォーマンスを向上させる可能性があります。n個の比較があるスイッチでは、平均的なケースでn / 2個の比較が期待できます。内部クラスを使用すると、アクション実行者とアクションリスナーの間に1:1の対応を設定できます。大規模なGUIでは、このような最適化はパフォーマンスに大きな影響を与える可能性があります。匿名のアプローチは次のようになります。

パブリッククラスSomeGUIはJFrameを拡張します{...ボタンメンバー宣言... protected void buildGUI(){button1 = new JButton(); button2 = new JButton(); ... button1.addActionListener(new java.awt.event.ActionListener(){public void actionPerformed(java.awt.event.ActionEvent e){//何かをする}}); ..ボタンごとに繰り返す

内部メンバークラスを使用すると、同じプログラムは次のようになります。

public class SomeGUI extends JFrame {...ボタンメンバー宣言//内部クラス定義クラスButton1HandlerはActionListenerを実装します{publicvoid actionPerformed(ActionEvent e){//何かを行う}} ...各ボタンの内部メンバークラスを定義するprotectedvoid buildGUI (){//ボタンを初期化しますbutton1 = new JButton(); button2 = new JButton(); ... //内部クラスアクションリスナーインスタンスを//ボタンごとに登録しますbutton1.addActionListener(new Button1Handler()); ..ボタンごとに繰り返す

内部クラスは親のすべてにアクセスできるため、モノリシックactionPerformed()実装で表示されるロジックを内部クラスに移動できます。

メンバークラスをコールバックとして使用することを好みます。しかし、それは個人的な好みの問題です。匿名クラスが多すぎるとコードが乱雑になると感じています。また、匿名クラスは1行または2行よりも大きいと、扱いにくくなる可能性があると感じています。

短所?

As with anything else, you have to take the good with the bad. Inner classes have their disadvantages. From a maintenance point of view, inexperienced Java developers may find the inner class difficult to understand. The use of inner classes will also increase the total number of classes in your code. Moreover, from a development point of view, most Java tools come up a bit short on their support of inner classes. For example, I use IBM's VisualAge for Java for my day-to-day coding. While inner classes will compile within VisualAge, there is no inner class browser or template. Instead, you must simply type the inner class directly into the class definition. That unfortunately makes browsing the inner class difficult. It is also difficult to type since you lose many of VisualAge's code completion aids when you type into the class definition or use an inner class.

Tony Sintesは、電気通信を専門とするObjectWaveのシニアコンサルタントです。Sun認定のJava1.1プログラマーおよびJava2開発者であるSintesは、1997年からJavaを使用しています。

このトピックの詳細

  • Sunの「InnerClassesSpecification」では、内部クラスについて詳しく説明しています。

    //java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html

このストーリー「内部クラス」は、もともとJavaWorldによって公開されました。