1

根据Oracle 网站上的 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;
    }
}

在上面,我可以使用 setterenum更改 , 的值。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 设计者保留了这个功能?

4

3 回答 3

5

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

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

为了使完整的枚举不可变:

  • 他们的实例成员也必须是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
}
于 2013-06-29T15:19:33.167 回答
4

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

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

但正如您所发现的,枚举实例不一定是不可变的。

它与您编写时完全相同:

public static final List MY_LIST = new ArrayList();

MY_LIST将始终引用同一个列表,但您可以添加到该列表或从该列表中删除。

于 2013-06-29T15:19:45.787 回答
1

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

于 2013-06-29T15:20:15.773 回答