enum 宣言は、インスタンス集合が固定された final クラスを定義します。各定数はそのクラスのインスタンスであり、
概念的には列挙型を E とする Enum<E> を継承します。ユーザー定義の enum は別のクラスを継承できません。
コンパイラーは values() と valueOf(String) を提供し、Enum は名前、ordinal、比較、シリアライズの規則を提供します。
インターフェースと定数固有の動作 #
enum はインターフェースを実装でき、その実装はすべての定数で共有することも、定数固有のクラス本体で提供することもできます。
enum Operation {
ADD { int apply(int a, int b) { return a + b; } },
SUBTRACT { int apply(int a, int b) { return a - b; } };
abstract int apply(int a, int b);
}各定数固有の本体はコンパイラーが生成する匿名サブクラスです。そのため仮想ディスパッチによってオーバーライドが選択されます。 外側の enum は閉じた集合のままなので、コンパイル時に戦略が既知であれば効果的な Strategy 実装になります。 拡張を独立して導入する必要がある場合は、注入するインターフェース実装を優先します。
定数固有の本体は enum の抽象メソッドを実装できます。動作を共有する場合は enum レベルの実装が適しています。 ライフサイクルを意図的にプロセス全体にする場合を除き、enum 定数から可変状態を排除します。 enum インスタンスは定義元のクラスローダーによって一度だけ初期化されるためです。
同一性、順序、コレクション #
enum のシリアライズはシングルトンの同一性を保持します。デシリアライズでは新しいインスタンスを割り当てず、名前で定数を解決します。
clone とリフレクションによる enum インスタンスの構築は禁止されています。enum の同一性には == を使い、
定数の追加や並べ替えで変わるため ordinal() の永続化は避けます。name() はソースレベルの安定性が明示的な契約の場合だけ永続化し、
長期保存データには外部コードフィールドの方が安全です。
Enum.compareTo は宣言順に定数を並べます。EnumSet は定数の ordinal を使って集合をコンパクトに表現し、
EnumMap は enum をキーにして値をインデックス化します。どちらも 1 つの enum 型を必要とし、その制約が自然な場合は汎用コレクションより適しています。
EnumSet<Operation> enabled = EnumSet.of(Operation.ADD);
EnumMap<Operation, String> labels = new EnumMap<>(Operation.class);
labels.put(Operation.ADD, "addition");
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)