内部クラスと無名クラス
クラス内に宣言されたクラスを内部クラス(インナークラス)といいます。また、内部クラスにはクラス名を宣言しない無名クラス(匿名クラス)もあります。
あるクラスのメンバ変数やメソッドに強く依存するクラスは、そのクラスの中に内部クラスとして記述する方が使いやすくなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class ClassInClass { private String classInClassMsg = "インナークラスの外のprivateメンバ変数にアクセスしました。" ; private class InnerClass { private String innerClassMsg = "インナークラスの中のprivateメンバ変数にアクセスしました。" ; void innerSpeak() { System.out.println( "インナークラスのメソッドがメッセージを出します。" ); System.out.println(classInClassMsg); System.out.println(innerClassMsg); } } void classInClassSpeak() { System.out.println( "クラス内でインナークラスのインスタンスを作り、そのメソッドを呼びます。" ); InnerClass inC = new InnerClass(); inC.innerSpeak(); } } |
インナークラスを定義したクラスのインスタンスを使ってインナークラスを使う処理
1 2 3 4 5 6 | public class ClassInClassSample { public static void main( String args[] ) { ClassInClass cic = new ClassInClass(); cic.classInClassSpeak(); } } |
実行結果
>java ClassInClassSample クラス内でインナークラスのインスタンスを作り、そのメソッドを呼びます。 インナークラスのメソッドがメッセージを出します。 インナークラスの外のprivateメンバ変数にアクセスしました。 インナークラスの中のprivateメンバ変数にアクセスしました。 > |
内部クラスからは同じクラス内のprivate修飾子の付いたメンバ変数、メソッドにもアクセスできます。
内部クラスはメソッド内にも作ることができます。その場合、その内部クラスはメソッド内でのみ機能します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class ClassInMethod { private String mainClassMsg = "インナークラスの外のprivateメンバ変数にアクセスしました。" ; void classInMethodSpeak() { class InnerClass { private String innerClassMsg = "インナークラスの中のprivateメンバ変数にアクセスしました。" ; void innerSpeak() { System.out.println( "インナークラスのメソッドがメッセージを出します。" ); System.out.println(mainClassMsg); System.out.println(innerClassMsg); } } System.out.println( "メソッド内でインナークラスのインスタンスを作り、そのメソッドを呼びます。" ); InnerClass inC = new InnerClass(); inC.innerSpeak(); } } |
インナークラスを定義したクラスのインスタンスを使ってインナークラスを使う処理
1 2 3 4 5 6 | public class ClassInMethodSample { public static void main( String args[] ) { ClassInMethod cim = new ClassInMethod(); cim.classInMethodSpeak(); } } |
実行結果
>java ClassInMethodSample メソッド内でインナークラスのインスタンスを作り、そのメソッドを呼びます。 インナークラスのメソッドがメッセージを出します。 インナークラスの外のprivateメンバ変数にアクセスしました。 インナークラスの中のprivateメンバ変数にアクセスしました。 > |
メソッド内で内部クラスを作る場合、内部クラスに名前を与えないクラスを無名クラスと呼びます。
無名クラスは、宣言から、実装、インスタンス化までをまとめて一文で記述できますが、その記述が通常のクラスの記述と異なるため注意が要ります。
名前が無いため継承が出来ませんから一代限りのシンプルな抽象クラスの実現やインターフェースの実装に使います。
new 抽象クラス名( ) { 無名クラス }; new インタフェース名( ) { 無名クラス }; |
インターフェースを無名クラスで実装するところを見てみましょう。
1 2 3 | interface Conversation{ public void greeting(); } |
インターフェースを実装し、インスタンス化して、インスタンスを利用する処理
7行目の}の後に;が必要なことに注意してください。
1 2 3 4 5 6 7 8 9 10 | public class NamelessClass { public static void main( String args[] ) { Conversation introduction= new Conversation(){ //インタフェースを無名クラスで実装し、即インスタンス化。 public void greeting(){ System.out.println( "私は無名クラスで実装されました。" ); } }; introduction.greeting(); } } |
実行結果
>java NamelessClass 私は無名クラスで実装されました。 > |
参考に、インターフェースを通常のクラスで実装し、そのクラスをインスタンス化して利用する場合を見てみましょう。
1 2 3 4 5 | class Talking implements Conversation { public void greeting(){ System.out.println( "私は名前のある通常クラスで実装されました。" ); } } |
そして、クラスをインスタンス化して利用する処理
1 2 3 4 5 6 | public class NamedClass { public static void main( String args[] ) { Talking introduction= new Talking(); introduction.greeting(); } } |
実行結果
>java NamedClass 私は名前のある通常クラスで実装されました。 > |
使う用途によっては無名クラスは簡潔に処理を記述できますが、用途は限定されるでしょう。自ら作ることは少ないかもしれませんが、一つだけで良いインターフェースの実現、たとえばGUI作成のためActionListenerインターフェースなどの実現などではよく使われます。