根据Oracle website上的Java教程:
枚举类型是一种特殊数据类型,它使变量成为一组预定义常量。变量必须等于为其预定义的值之一。
我同意这些值是预定义的。但他们真的是常数吗?
可以通过更改数据成员的值来更改enum
值。那么,它们在逻辑上可以称为常量吗?
假设我有enum
如下:
public enum Color
{
BLACK("0x000000"), WHITE("0xffffff");
Color(String rgbValue)
{
this.rgbValue = rgbValue;
}
private String rgbValue;
public String getRgbValue()
{
return this.rgbValue;
}
public void setRgbValue(String rgbValue)
{
this.rgbValue = rgbValue;
}
}
在上面enum
中,我可以使用setter更改rgbValue
的值。如果我执行以下语句集,则BLACK
的状态会发生变化。
System.out.println(Color.BLACK.getRgbValue());
Color.BLACK.setRgbValue("0x000010");
System.out.println(Color.BLACK.getRgbValue());
上面的代码产生以下输出:
0x000000
0x000010
那么我们真的可以将enum
值称为常量吗?是否应该防止enum
值的状态发生变化?默认情况下,enum
中的数据成员不应声明为final
,以便enum
可以真正称为常量吗?
如果enum
的状态不守恒,那么除了创建的预定义数量的对象之外,正常class
和enum
之间有什么区别?
或者有一个特定的原因,为什么Java设计师保留了这个功能?
答案 0 :(得分:5)
什么是不可变的,默认情况下static final
是枚举值(关于它们的可见性修饰符,即public
,private
或默认值,它是从声明继承的enum本身)。
但这些价值观本身就属于阶级;因此,这种不变性不适用于实例变量,如果有的话。
为了让完整的枚举成为不可变的:
final
,在枚举使用最简单的情况下(即public class MyEnum { VALUE1, VALUE2 }
),实例变量不变性不是问题,因为它们没有。
但是只要将实例变量添加到枚举中,就会应用与这些实例变量相同的约束,就像它们对任何其他Java类一样(即使所述类是final
)。因为,最终,枚举实例本身就是类。他们恰好是单身人士,final
和extends Enum<ThemSelves>
。
在您的示例中,您的rgbValue
必须为final
。这样,由于String
是一个不可变类,你的枚举将“真正”成为不可变的。
奇怪的是,您可以想到的最佳默认不变性是在...接口:
public interface Foo
{
int bar = 3; // bar is "public", "static" AND "final" by default
}
答案 1 :(得分:4)
Color.BLACK
是一个常量,在整个应用程序中(类加载器更具体),只有一个与Color.BLACK
和Color.BLACK
对应的枚举实例总是指那个实例。
你不能写:Color.BLACK = Color.WHITE;
例如。
但是你发现的枚举实例并不一定是不可变的。
与你写作时完全一样:
public static final List MY_LIST = new ArrayList();
MY_LIST
将始终引用相同的列表,但您可以在该列表中添加或删除。
答案 2 :(得分:1)
使用枚举中的元素意味着您(比方说)对内存中的一堆对象的常量引用池。没有人说这些对象必须是不可变的,因此你可以改变它们的状态。但是引用Color.BLACK
将始终是同一个。