列挙型がコンパイル時定数を取り除くための答えである場合、言語設計者は、なぜ任意のメソッドとフィールドを許可し、列挙型に任意のインターフェイスを実装する機能を提供したのでしょうか? これらのメソッドは、Enum インスタンスの状態を変更することはできませんか? それらが状態の変更を許可されている場合、列挙型の不変式、つまりいくつかの定数をエクスポートする型は IMHO を破ります。
3 に答える
Java 列挙型は、実際には、コンパイラとランタイムによって特別な処理が行われる単なるクラスです。そうです、列挙型インスタンスのメソッド呼び出しは確かにその状態を変更できます。「その後、列挙型の不変式、つまりいくつかの定数をエクスポートする型が壊れる」という意味がわかりません。
列挙型は定数の集まりにしかならないと誰が言いますか? 列挙型の本質は、名前で参照できる定義済みの固定数のインスタンスがあり、Java 列挙型がそれを実装することです。しかし、言語がそれよりも強力な列挙型を持つことを許可されないのはなぜでしょうか?
余分なパワーが必要ない場合は、誰も強制的に使用することはありません。フィールドやメソッドのない Java 列挙型を持つことができ、C 列挙型とほとんど同じように動作します。
列挙型はコンパイル時の定数ですが、そのメンバーはそうではありません。通常、実行時に列挙メンバーを変更することはお勧めできませんが、可能です。このため、コンパイル時の定数が呼び出される場所 (たとえば、注釈パラメーター) で列挙型のメンバーを使用することはできません。
Java では、物事を台無しにしようとすると、実際に定数になるものはほとんどありません。たとえば、String 定数には char 配列が含まれます。配列は不変ではありません。インライン化された文字列定数を使用して作成できる混乱の例を次に示します。
public static void main(final String[] args) throws Exception {
final Field valueField = String.class.getDeclaredField("value");
valueField.setAccessible(true);
System.arraycopy("frog".toCharArray(), 0,
(char[]) valueField.get(Boolean.TRUE.toString()), 0, 4);
System.out.println(Boolean.parseBoolean("frog")); // true
System.out.println(Boolean.parseBoolean("true")); // false
}
そのため、ほとんどの場合、Java 定数は、アプリケーションの動作が適切である限り、単なる定数です。
なぜ言語設計者は、任意のメソッドとフィールドを許可し、Enum に任意のインターフェイスを実装する機能を提供したのですか?
その理由は、switch ステートメントをポリモーフィズムに置き換えることを許可し、一般に、データに対してメソッドを定義できるようにすることで、プログラムをよりオブジェクト指向にするためです。
「タイプ セーフな列挙型パターン」を検索します。Java Enum は、言語レベルでのこの設計パターンの実装です。