Javaでは、クラス内に別のクラスを定義できます。これは「内部クラス」と呼ばれ、大きく分けて4種類あります。
- メンバー内部クラス
- ローカル内部クラス
- スタティック内部クラス
- 匿名内部クラス
メンバー内部クラス
メンバー内部クラスは、外部クラスのメンバー変数やメソッドと同じように、クラスの内部に定義されます。
class OuterClass {
private int outerField = 10;
private void outerMethod() {}
class InnerClass {
private int innerField = 0;
public void innerMethod() {}
}
}
この例では、`OuterClass`が外部クラス、`InnerClass`が内部クラスです。内部クラスは外部クラスのprivateメンバーにもアクセスできます。
public class InnerClassDemo {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.callInnerMethod();
}
}
class OuterClass {
private int outerField = 10;
private void outerMethod() {
System.out.println("外部クラスのprivateメソッド呼び出し");
}
public void callInnerMethod() {
InnerClass inner = new InnerClass();
inner.accessOuterMembers();
}
class InnerClass {
public void accessOuterMembers() {
outerField = 5; // 外部クラスのprivateフィールドにアクセス
outerMethod(); // 外部クラスのprivateメソッドにアクセス
System.out.println("変更後の外部フィールド値: " + outerField);
}
}
}
// 出力:
// 外部クラスのprivateメソッド呼び出し
// 変更後の外部フィールド値: 5
内部クラスのインスタンスは、単独で生成することはできません。必ず外部クラスのインスタンスを介して生成する必要があります。
public class InnerClassDemo {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass(); // 外部クラスのインスタンス経由で生成
// または OuterClass.InnerClass inner = new OuterClass().new InnerClass();
inner.accessOuterMembers();
}
}
class OuterClass {
private int outerField = 10;
private void outerMethod() {
System.out.println("外部クラスのprivateメソッド呼び出し");
}
class InnerClass {
public void accessOuterMembers() {
outerField = 5;
outerMethod();
System.out.println("変更後の外部フィールド値: " + outerField);
}
}
}
// 出力:
// 外部クラスのprivateメソッド呼び出し
// 変更後の外部フィールド値: 5
内部クラス内で、同名のフィールドが存在する場合のアクセス方法も確認しましょう。
public class InnerClassDemo {
public static void main(String[] args) {
OuterClass.InnerClass inner = new OuterClass().new InnerClass();
inner.displayFields();
}
}
class OuterClass {
private int field = 10;
class InnerClass {
private int field = 20;
public void displayFields() {
int field = 30;
System.out.println("ローカル変数 field: " + field);
System.out.println("内部クラスのフィールド: " + this.field);
System.out.println("外部クラスのフィールド: " + OuterClass.this.field);
}
}
}
// 出力:
// ローカル変数 field: 30
// 内部クラスのフィールド: 20
// 外部クラスのフィールド: 10
ローカル内部クラス
ローカル内部クラスは、メソッド内やブロック内に定義され、そのスコープ内でのみ有効です。
public class InnerClassDemo {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.methodWithLocalInnerClass(15);
}
}
class OuterClass {
private int outerField = 10;
public void methodWithLocalInnerClass(final int parameter) {
int localVariable = 10;
// localVariable = 11; // finalでない変数はアクセスできない(Java 8以降は緩和)
class LocalInnerClass {
public void display() {
outerField = 11; // 外部クラスのフィールドにはアクセス可能
System.out.println("変更後の外部フィールド値: " + outerField);
System.out.println("引数 parameter: " + parameter); // final引数にはアクセス可能
// System.out.println("ローカル変数 localVariable: " + localVariable); // finalでないローカル変数にはアクセスできない
}
}
LocalInnerClass localInner = new LocalInnerClass();
localInner.display();
}
}
メソッドの外からはローカル内部クラスにアクセスできません。
スタティック内部クラス
`static` キーワードを付けて定義された内部クラスです。外部クラスのインスタンス化なしにアクセスできますが、外部クラスのインスタンスメンバー(非staticフィールドやメソッド)には直接アクセスできません。外部クラスのstaticメンバーのみアクセス可能です。
public class InnerClassDemo {
public static void main(String[] args) {
// 外部クラスのインスタンス化なしでスタティック内部クラスにアクセス
OuterClass.StaticInnerClass staticInner = new OuterClass.StaticInnerClass();
staticInner.accessOuterStaticMembers();
OuterClass.StaticInnerClass.staticMethodCall(); // スタティックメソッドの呼び出し
}
}
class OuterClass {
private int instanceField = 10;
private static int staticField = 11;
private void instanceMethod() {
System.out.println("インスタンスメソッド");
}
private static void staticMethod() {
System.out.println("スタティックメソッド");
}
static class StaticInnerClass {
public void accessOuterStaticMembers() {
// instanceField = 11; // エラー: インスタンスフィールドにはアクセスできない
// instanceMethod(); // エラー: インスタンスメソッドにはアクセスできない
staticField = 12; // スタティックフィールドにはアクセス可能
staticMethod(); // スタティックメソッドにはアクセス可能
System.out.println("変更後のスタティックフィールド値: " + staticField);
}
public static void staticMethodCall() {
// instanceField = 11; // エラー
// instanceMethod(); // エラー
staticField = 13; // スタティックフィールドにはアクセス可能
staticMethod(); // スタティックメソッドにはアクセス可能
System.out.println("スタティックメソッドからのスタティックフィールド値: " + staticField);
}
}
}
スタティック内部クラスの非staticメソッドを呼び出す場合は、そのクラスのインスタンスを生成します。
// 非staticメソッドの呼び出し
OuterClass.StaticInnerClass innerInstance = new OuterClass.StaticInnerClass();
innerInstance.accessOuterStaticMembers();
スタティック内部クラスのstaticメソッドを呼び出す場合は、クラス名から直接呼び出します。
// staticメソッドの呼び出し
OuterClass.StaticInnerClass.staticMethodCall();
匿名内部クラス
匿名内部クラスは、クラスを継承またはインターフェースを実装する際に、その場でクラスを定義し、インスタンスを生成する方法です。クラス宣言を省略します。
(※このセクションは、詳細な説明が不足しているため、ここでは割愛します。)