内部クラス

JDK1.1以降からクラスの中でクラスが作れるようにになり、 内部クラスとか、入れ子クラス、ネストクラス などと呼ばれます。
またこれまでの紹介で作成した入れ子(ネスト)になっていないクラスを トップレベルクラスと呼ぶことあります。

さてこの内部クラスは、static宣言のクラスと、そうでないクラスがあり、使い方が大きく異なります。

static 内部クラス

以下で、TESTクラスの中でSubClsの 名前のstatic内部クラスを作っています。
Test.javaをコンパイルすると、Test.classの外側クラスと、 その内部クラスになっているTest$SubCls.class の2つのファイルが生成されます。
これを使用しているファイルTestCheck.java と、その実行を示します。
static宣言の内部クラスは、本質的にこれまでの最も外側で作るクラスと変わりません。 (後述するstatic宣言なしの内部クラスと違って、 内側クラスから外側のインスタンスメンバを直接アクセスできません。)

public class Test{
	public int d = 999;
	
	public static class SubCls{
		public int k = 25;
		public static String z = "WXYZ";
		
		public void func(){
			System.out.println(" SubClsクラスのfunc実行:" + z + k);
			// System.out.println(d); //dをアクセスできずにエラー 
		}
		public static void stFunc(){
			System.out.println("SubClsクラスのstaticメソッド実行:" + z);//zはアクセス可能
		}
	}
	
	public void rootFunc(){
		//k = 10; //SubClsのインスタンス変数は、外部からアクセス不可
		System.out.println("Test内のfunc実行");
		SubCls sub = new SubCls();
		sub.func();
	}
}
public class TestCheck
{
	public static void main(String []args){
		Test t = new Test();
		t.rootFunc();
		
		Test.SubCls.z = "ABC";
		Test.SubCls.stFunc();
		
		Test.SubCls tSub = new Test.SubCls();
		tSub.func();
	}
}
Z:\java>java TestCheck
Test内のfunc実行
 SubClsクラスのfunc実行:WXYZ25
SubClsクラスのstaticメソッド実行:ABC
 SubClsクラスのfunc実行:ABC25

Z:\java>







static内部クラスは、上記の特徴があります。上記ラジオボタンで位置 を確認ください。
staticのクラスは、ネスト(入れ子)クラスですが、機能的にトップレベルクラスと同じなので、 ネスト トップレベルクラスと呼ばれることがあります。

内部クラス(static宣言でない)

以下で、TESTクラスの中でSubClsの 名前の内部クラスを作っています。
上記のstaticクラスと違って、 外側のクラスのオブジェクトの中でしか存在できません。 つまり、外側のインスタンスの中でのみ生成でき、 static内部クラスのように単体で生成できません。
ですが、生成時の位置した外側クラスのインスタンス変数をアクセスすることができます。
またこのstatic宣言でない内部クラスは、 static宣言のフィールドやメソッドを作ることができません。

これを使用しているファイルTestCheck.java と、その実行を示します。 上記static内部クラスと比較ください。

public class Test
{
	public int d = 999;
	public int k2 = 2;

	public class SubCls
	{
		public int k = 25;
		public int k2 = 22;
		public static final String z = "WXYZ";//static 宣言を持つことはできませんが、finalが付けば可能。

		public void func(){
			System.out.println(" SubClsクラスのfunc実行:" + k + z);
			System.out.println(d); //dをアクセスで可能
			System.out.println("自身の変数k2=" + this.k2);
			System.out.println("明示的に外側の変数k2=" + Test.this.k2);
		}
		//public static void stFunc() { } //static 宣言を持つことはできません。
	}

	public void rootFunc(){
		//k = 10; //SubClsのインスタンス変数は、外部からアクセス不可
		System.out.println("Test内のfunc実行");
		SubCls sub = new SubCls();
		sub.func();
	}
}
public class TestCheck
{
	public static void main(String[] args){
		Test t = new Test();
		t.rootFunc();

		//Test.SubCls tSub = new Test.SubCls();//単体 エラーです。
		//tSub.func();
	}
}
Z:\java>javac TestCheck.java

Z:\java>java TestCheck
Test内のfunc実行
 SubClsクラスのfunc実行:25WXYZ
999
自身の変数k2=22
明示的に外側の変数k2=2

Z:\java>


内部クラスは、上記の特徴があります。上記ラジオボタンで位置 を確認ください。
上記で、Test.this.k2の表現は、SubClsのk2でなく、Testのk2です。
内部クラスで、外側のインスタンス変数を明示的に表現する場合は 外側クラス名.thisとします。

なお、 Test.javaをコンパイルすると、 Test.classの外側クラスと、 その内部クラスになっている Test$SubCls.class の2つの ファイルが生成されことはstaticの内部クラスと同じです。

後述する匿名クラスもstaticがない内部クラスの分類に位置し、この使い方の頻度は多いようです。 以降で単に内部クラスという場合、static宣言をつけない内部クラスを指しています。