Java 枚举类型中的方法能否更改枚举实例的状态?

Java 枚举类型中的方法能否更改枚举实例的状态?,java,enums,Java,Enums,如果枚举是摆脱编译时常量的一个答案,那么为什么语言设计人员提供了允许在枚举上使用任意方法和字段并实现任意接口的工具?这些方法永远无法更改枚举实例的状态,或者它们可以吗?如果允许它们更改状态,则枚举类型的不变量(即导出几个常量的某个类型)将破坏IMHO。Java枚举实际上只是经过编译器和运行时特殊处理的类。所以,是的,对枚举实例的方法调用肯定会更改其状态。我不确定你所说的“那么枚举类型的不变量(即导出几个常量的类型)将被破坏”是什么意思 谁说枚举只能是一堆常量?枚举类型的本质是拥有预定义的固定数量

如果枚举是摆脱编译时常量的一个答案,那么为什么语言设计人员提供了允许在枚举上使用任意方法和字段并实现任意接口的工具?这些方法永远无法更改枚举实例的状态,或者它们可以吗?如果允许它们更改状态,则枚举类型的不变量(即导出几个常量的某个类型)将破坏IMHO。

Java枚举实际上只是经过编译器和运行时特殊处理的类。所以,是的,对枚举实例的方法调用肯定会更改其状态。我不确定你所说的“那么枚举类型的不变量(即导出几个常量的类型)将被破坏”是什么意思

谁说枚举只能是一堆常量?枚举类型的本质是拥有预定义的固定数量的实例,可以通过名称引用这些实例,Java枚举实现了这一点。但是为什么不允许一种语言拥有比它更强大的枚举呢

如果你不想要额外的能量,没有人强迫你使用它。您可以使用没有字段或方法的Java枚举,它们的行为与C枚举非常相似

为什么语言设计者提供了允许任意方法和字段的工具,并在枚举上实现任意接口

原因是允许用多态性替换switch语句,并且通常允许在数据上定义方法,从而使程序更面向对象


搜索“类型安全枚举模式”。Java枚举是这种设计模式在语言级别的实现

枚举是编译时常量,但其成员不是。在运行时更改枚举成员通常不是一个好主意,但这是可能的。因此,不能在调用编译时常量的地方(例如,在注释参数中)使用枚举的成员

当你努力把事情搞砸时,Java中几乎没有任何东西是不变的。例如,字符串常量包含字符数组。数组不是不变的。下面是一个使用内联字符串常量可以造成混乱的示例:

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常量在大多数情况下都是常量。

我的意思是枚举是不可变的,提供方法可以改变此不变量,因为它们可能会改变枚举的状态。@Geek:枚举实例的数量、名称和标识是不可变的。它们可以具有可变状态,这并不会改变这一点。您在哪里看到问题?因为字段必须是最终字段(并且由编译器强制执行),所以这无关紧要。否则,枚举实例的不变性将无法保持。这些字段只是将一些数据与实例相关联。它们永远不能改变实例本身的状态。@Geek:那不是真的-编译器会乐意接受枚举中的非最终字段。我不知道你是从哪里得到“枚举实例必须是不可变的”这个想法的。@Geek你可以将你的枚举写为不可变的,并将其用于常量(这也是大多数情况下使用枚举的方式),这并不意味着这是枚举的唯一可能性或目标。而且,即使编译器将所有字段都约束为final,也无济于事。请注意,Java没有C/C++(const-Foo*/const-Foo&)的const-pointer/const-ref等价物