枚举真的是常量吗?枚举的数据成员是否应默认为final?

时间:2013-06-29 15:16:21

标签: java enums

根据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的状态不守恒,那么除了创建的预定义数量的对象之外,正常classenum之间有什么区别?

或者有一个特定的原因,为什么Java设计师保留了这个功能?

3 个答案:

答案 0 :(得分:5)

什么是不可变的,默认情况下static final是枚举值(关于它们的可见性修饰符,即publicprivate或默认值,它是从声明继承的enum本身)。

但这些价值观本身就属于阶级;因此,这种不变性不适用于实例变量,如果有的话。

为了让完整的枚举成为不可变的:

  • 他们的实例成员也必须是final
  • 并且这些实例成员本身也必须是不可变的。

在枚举使用最简单的情况下(即public class MyEnum { VALUE1, VALUE2 }),实例变量不变性不是问题,因为它们没有。

但是只要将实例变量添加到枚举中,就会应用与这些实例变量相同的约束,就像它们对任何其他Java类一样(即使所述类是final)。因为,最终,枚举实例本身就是类。他们恰好是单身人士,finalextends Enum<ThemSelves>

在您的示例中,您的rgbValue必须为final。这样,由于String是一个不可变类,你的枚举将“真正”成为不可变的。

奇怪的是,您可以想到的最佳默认不变性是在...接口:

public interface Foo
{
    int bar = 3; // bar is "public", "static" AND "final" by default
}

答案 1 :(得分:4)

Color.BLACK是一个常量,在整个应用程序中(类加载器更具体),只有一个与Color.BLACKColor.BLACK对应的枚举实例总是指那个实例。

你不能写:Color.BLACK = Color.WHITE;例如。

但是你发现的枚举实例并不一定是不可变的。

与你写作时完全一样:

public static final List MY_LIST = new ArrayList();

MY_LIST将始终引用相同的列表,但您可以在该列表中添加或删除。

答案 2 :(得分:1)

使用枚举中的元素意味着您(比方说)对内存中的一堆对象的常量引用池。没有人说这些对象必须是不可变的,因此你可以改变它们的状态。但是引用Color.BLACK将始终是同一个。