内部クラス
クラス内で定義されたクラスは内部クラスと呼ばれます。内部クラスを含むクラスは外部クラスまたはホストクラスとも呼ばれます。内部クラスは外部クラス内に隠蔽されており、同じパッケージ内の他のクラスからのアクセスは許可されません。内部クラスのメンバーは外部クラスの非公開データに直接アクセスできます。これは内部クラスが外部クラスのメンバーとして扱われるためです。同じクラスのメンバー間は相互にアクセスできます。しかし、外部クラスは内部クラスの実装詳細(内部クラスのメンバ変数など)にアクセスすることはできません。
非静的内部クラス
// 外部クラス
public class Container {
private int value;
public Container(int value) {
this.value = value;
}
// 非静的内部クラス
public class NestedElement {
private String label;
private int quantity;
public NestedElement(String label, int quantity) {
this.label = label;
this.quantity = quantity;
}
public void display() {
// 内部クラスから外部クラスの非公開メンバーにアクセス可能
System.out.println("外部クラスの非公開変数: " + value);
}
}
}
// テストクラス
public class TestNestedClass {
public static void main(String[] args) {
NestedElement element = new Container(30).new NestedElement("製品A", 15);
element.display();
}
}
静的内部クラス
内部クラスがstatic修飾子で修飾されると、静的内部クラスになります。静的内部クラスは、クラス変数、クラスメソッド、静的コードブロックと同様の地位を持ちます。staticキーワードの役割は、クラスのメンバーをインスタンス関連ではなくクラス関連にすることです。つまり、staticで修飾されたメンバーは単一のオブジェクトではなく、クラス全体に属します。
// 外部クラス
public class StaticContainer {
static int globalValue = 100;
int instanceValue = 200;
// 静的内部クラス
static class StaticNested {
public void print() {
// 外部クラスのクラスメンバーにアクセス可能
System.out.println("グローバル値: " + globalValue);
// コンパイルエラー: 静的内部クラスは外部クラスのインスタンス変数にアクセスできない
// System.out.println(instanceValue);
}
}
}
// テストクラス
public class TestStaticNested {
public static void main(String[] args) {
StaticNested nested = new StaticContainer.StaticNested();
nested.print();
}
}
ローカル内部クラス
内部クラスをメソッド内で定義すると、その内部クラスはローカル内部クラスになります。ローカル内部クラスはそのメソッド内でのみ有効です。ローカル内部クラスは外部クラスのメソッド以外の場所で使用できないため、アクセス修飾子やstatic修飾子で修飾することはできません。
// 外部クラス
public class MethodContainer {
public void process() {
// ローカル内部クラス
class LocalProcessor {
public void execute() {
System.out.println("ローカル内部クラスのメソッドが実行されました");
}
}
// メソッド内でのみ使用可能
LocalProcessor processor = new LocalProcessor();
processor.execute();
}
}
匿名内部クラス
匿名内部クラスは、名前を持たない内部クラスです。インターフェースを実装するか、既存のクラスを拡張するために使用されます。匿名内部クラスは通常、インスタンス化と同時に定義されます。
// インターフェース
interface Runner {
void run();
}
// 匿名内部クラスの使用例
public class AnonymousExample {
public static void main(String[] args) {
// 匿名内部クラスを使用してインターフェースの実装
Runner runner = new Runner() {
@Override
public void run() {
System.out.println("匿名内部クラスで実行中");
}
};
runner.run();
// 匿名内部クラスを使用して既存クラスを拡張
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("匿名内部クラスでスレッド実行中");
}
};
thread.start();
}
}
列挙型
特定の場合において、クラスのオブジェクトが有限且つ固定されている場合、Javaではそのようなクラスを列挙型と呼びます。列挙型と通常のクラスの違いは以下の通りです:
- 列挙型は1つ以上のインターフェースを実装できます
- enumキーワードで定義された列挙型はデフォルトでjava.lang.Enumクラスを継承します
- 列挙型は明示的に他の親クラスを継承できません
// 列挙型の定義
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
// 列挙型の使用
public class EnumExample {
public static void main(String[] args) {
Day today = Day.FRIDAY;
System.out.println("今日は: " + today);
// 列挙型のメソッドを使用
for (Day day : Day.values()) {
System.out.println(day);
}
}
}