枚举和最终变量有何区别?

6
我正在努力学习枚举以更好地理解它们。从Java文档中,我获取了以下信息: “枚举类型是一种特殊的数据类型,使变量成为预定义常量的集合。” 对我来说,这听起来非常像final变量。 那么,真正的区别是什么呢?在何时使用其中之一?枚举只是一组final变量吗?

1
还可以看看这个帖子stackoverflow:Java枚举变量是静态的吗这里也有解释。 - dehlen
6个回答

6
区别在于枚举提供了类型安全。让我们看一个enum
public enum MuEnum {
    FIRST("First"), SECOND("Second");

    private String value;

    MyEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

考虑以下例子:

public void myMethod(MyEnum parameter) { .. }

在这里,你只能传递MyEnum的值(FIRSTSECOND),如果你的方法签名为:
public void myMethod(String parameter) { .. }

您可以传递无效参数(某个字符串的内容与“First”或“Second”不同)。

3

当你有一个像 enum 的枚举时

public enum MyEnum {
   FIRST_COSTANT, SECOND_CONSTANT;
}

你实际拥有的是
public class /* enum */ MyEnum extends Enum<MyEnum> {
    private Enum() {}
    public final static MyEnum FIRST_CONSTANT = new MyEnum() {};
    public final static MyEnum SECOND_CONSTANT = new MyEnum() {};    
    ... // methods     
}

因此,在这个意义上,它们是相同的。

这在Java语言规范这里中有解释。

除了从枚举类型E继承的成员之外, 对于每个名为n的已声明枚举常量,枚举类型都有一个隐式声明的公共静态常量字段n,类型为E。这些字段被认为是按照相应的枚举常量的顺序声明的,在枚举类型中明确声明的任何静态字段之前。每个这样的字段都被初始化为与其对应的枚举常量。每个这样的字段也被认为带有与相应枚举常量相同的注释。当初始化相应的字段时,枚举常量被创建。


每个枚举条目都是一个子类,而不仅仅是一个实例。 - msangel

3

有一个很大的区别:首先,enum 不是变量,而是类型。一个 final 变量,比如说一个 int,可以有一个单一的、预设值,在众多可能的 int 值中选择一个,而 enum 变量 (也可以是 final) 可以从您在定义 enum 时声明的集合中选择一个值。

这里是一个例子:

enum Color {Red, Green, Blue;}

上面的声明并没有定义一个变量。它定义了一组值,如果您选择声明一个Color类型的变量,它就可以拥有这些值:

Color backgroundColor = Color.Red;

现在你有一个非最终的枚举类型变量Color。它的值可以改变,但必须是enum定义的三个值之一。
实际上,在模拟具有固定状态数量的事物并为其命名时,您使用enum。您也可以使用一个或多个final变量 - 实际上,在enum被引入之前这种做法已经很常见。例如,Java的Calendar类使用static final int常量表示日期的各个部分,其中enum可能效果更好。

2
我认为枚举不是final的原因在于您可以为枚举描述符中的每个字段定义一个匿名子类。
从文档中可以看到:
枚举类型(§8.9)不能声明为抽象的;这样做会导致编译时错误。
枚举类型默认为final,除非它包含至少一个具有类体的枚举常量。
显式声明枚举类型为final是编译时错误。
嵌套枚举类型默认为静态的。可以显式声明嵌套枚举类型为静态的。
此外,需要指出的是,如果我们将一个类标记为final,则意味着它们不能被继承。但是,当涉及到枚举时,默认情况下它们是不能被继承的。

1
在某种意义上,是的。以下陈述大致等价:

// This...
final int FIRST = 0;
final int SECOND = 1;

// Is roughly equivalent to this.
enum Ordering = { FIRST, SECOND };

区别在于类型安全。由于Ordering枚举命名了一个新类型,您可以创建一个接受Ordering而不是int的函数。这确保在编译时避免意外传递超出边界值(例如2)到期望Ordering的函数中。
void foo(Ordering order) {;}

foo(FIRST); // This works
foo(3); // This causes an error at compile time

0

当你知道一个类型会有多少实例时,就可以使用枚举。是的,在引入枚举之前,使用静态的 final 变量。

枚举提供了一些简单静态 final 变量所没有的优点:

  • 它们有类型。
  • 它们带有一些有用的方法,例如 valueOf,该方法允许按名称查找它们或枚举它们。
  • 每个实例都可以覆盖枚举的方法,以提供特定的行为。
  • 枚举确保除了已定义的实例外,不会有任何其他类实例存在,而不必设置构造函数为私有或其他可以通过反射来绕过的技巧。因此,这是实现一些模式(如 Singleton 模式)的好方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接