列挙型と内部クラス

このレッスンでは、列挙型と内部クラス——Javaの特殊なクラスを学びます。

列挙型

列挙型は固定された定数のセットを定義するために使用されます。

列挙型の定義

JAVA
public enum Season {
    SPRING, SUMMER, AUTUMN, WINTER
}

列挙型の使用

JAVA
public class EnumDemo {
    public static void main(String[] args) {
        Season season = Season.SPRING;
        
        switch (season) {
            case SPRING:
                System.out.println("春");
                break;
            case SUMMER:
                System.out.println("夏");
                break;
            case AUTUMN:
                System.out.println("秋");
                break;
            case WINTER:
                System.out.println("冬");
                break;
        }
    }
}

列挙型の属性とメソッド

JAVA
public enum Season {
    SPRING("春", 1),
    SUMMER("夏", 2),
    AUTUMN("秋", 3),
    WINTER("冬", 4);
    
    private String name;
    private int order;
    
    // コンストラクタ
    Season(String name, int order) {
        this.name = name;
        this.order = order;
    }
    
    // getter
    public String getName() {
        return name;
    }
    
    public int getOrder() {
        return order;
    }
}

一般的なenumメソッド

メソッド 説明
values() すべてのenum値 Season.values()
valueOf() 文字列からenumへ Season.valueOf("SPRING")
ordinal() enumインデックス Season.SPRING.ordinal() → 0
name() enum名 Season.SPRING.name() → "SPRING"

例:enumメソッド

JAVA
public class EnumMethodDemo {
    public static void main(String[] args) {
        // すべてのenum値を反復
        for (Season s : Season.values()) {
            System.out.println(s.ordinal() + ": " + s.getName());
        }
        
        // 文字列からenumへ
        Season spring = Season.valueOf("SPRING");
        System.out.println(spring.getName());  // 春
        
        // enumを比較
        System.out.println(Season.SPRING == Season.SPRING);  // true
        System.out.println(Season.SPRING.equals(Season.SPRING));  // true
    }
}
▶ 試してみよう

例:曜日enum

JAVA
public enum Weekday {
    MONDAY("月曜日", true),
    TUESDAY("火曜日", true),
    WEDNESDAY("水曜日", true),
    THURSDAY("木曜日", true),
    FRIDAY("金曜日", true),
    SATURDAY("土曜日", false),
    SUNDAY("日曜日", false);
    
    private String name;
    private boolean isWorkday;
    
    Weekday(String name, boolean isWorkday) {
        this.name = name;
        this.isWorkday = isWorkday;
    }
    
    public String getName() {
        return name;
    }
    
    public boolean isWorkday() {
        return isWorkday;
    }
}

public class WeekdayDemo {
    public static void main(String[] args) {
        for (Weekday day : Weekday.values()) {
            String type = day.isWorkday() ? "平日" : "週末";
            System.out.println(day.getName() + " - " + type);
        }
    }
}
▶ 試してみよう

内部クラス

内部クラスは別のクラスの内部に定義されたクラスです。

メンバ内部クラス

JAVA
public class Outer {
    private int x = 10;
    
    // メンバ内部クラス
    public class Inner {
        public void show() {
            // 外部クラスのprivateメンバーにアクセス可能
            System.out.println("x = " + x);
        }
    }
    
    public void test() {
        Inner inner = new Inner();
        inner.show();
    }
}

public class InnerClassDemo {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.show();  // x = 10
    }
}

静的内部クラス

JAVA
public class Outer {
    private static int x = 10;
    private int y = 20;
    
    // 静的内部クラス
    public static class StaticInner {
        public void show() {
            // 外部クラスの静的メンバーにのみアクセス可能
            System.out.println("x = " + x);
            // System.out.println("y = " + y);  // コンパイルエラー!
        }
    }
}

public class StaticInnerDemo {
    public static void main(String[] args) {
        // 外部クラスのオブジェクトを作成する必要がない
        Outer.StaticInner inner = new Outer.StaticInner();
        inner.show();  // x = 10
    }
}

ローカル内部クラス

JAVA
public class Outer {
    public void method() {
        // ローカル内部クラス:メソッド内に定義
        class LocalInner {
            public void show() {
                System.out.println("ローカル内部クラス");
            }
        }
        
        LocalInner inner = new LocalInner();
        inner.show();
    }
}

無名内部クラス

JAVA
public interface Greeting {
    void greet(String name);
}

public class AnonymousDemo {
    public static void main(String[] args) {
        // 無名内部クラス
        Greeting hello = new Greeting() {
            @Override
            public void greet(String name) {
                System.out.println("Hello, " + name + "!");
            }
        };
        
        hello.greet("Alice");  // Hello, Alice!
        
        // Lambda短縮形(関数型インターフェース)
        Greeting hi = name -> System.out.println("Hi, " + name + "!");
        hi.greet("Bob");  // Hi, Bob!
    }
}

例:イベント処理のための無名内部クラス

JAVA
public interface OnClickListener {
    void onClick(String button);
}

public class Button {
    private String text;
    private OnClickListener listener;
    
    public Button(String text) {
        this.text = text;
    }
    
    public void setOnClickListener(OnClickListener listener) {
        this.listener = listener;
    }
    
    public void click() {
        if (listener != null) {
            listener.onClick(text);
        }
    }
}

public class ButtonDemo {
    public static void main(String[] args) {
        Button btn = new Button("送信");
        
        // 無名内部クラス
        btn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(String button) {
                System.out.println(button + "がクリックされました");
            }
        });
        
        btn.click();  // 送信がクリックされました
    }
}
▶ 試してみよう

内部クラスの比較

タイプ 場所 外部クラスへのアクセス 作成方法
メンバ内部クラス クラス内 すべてのメンバー outer.new Inner()
静的内部クラス クラス内 静的メンバー new Outer.Inner()
ローカル内部クラス メソッド内 すべてのメンバー + ローカルfinal メソッド内で作成
無名内部クラス 任意の場所 ローカル内部クラスと同じ new Interface(){}

❓ よくある質問

Q いつenumを使用すべきですか?
A 季節、曜日、状態など、固定された定数のセットを定義するとき。
Q いつ無名内部クラスを使用すべきですか?
A 簡単なインターフェース実装、特にイベントコールバックに。Java 8以降、関数型インターフェースにはLambdaが推奨されます。
Q 内部クラスは何に使用されますか?
A コールバックの実装、外部クラスのプライベートメンバーへのアクセス、関連するクラスの整理。

📖 まとめ

📝 演習

  1. 季節enum: 季節名と温度範囲を持つSeason enumを定義
  2. 状態機械: enumを使用して注文状態(保留、支払い済み、発送済み、完了)を実装
  3. 無名内部クラス: 無名内部クラスを使用してComparatorソートを実装

次のレッスン

次のレッスンでは、例外処理を学びます — プログラムでのエラー処理方法。

100%