Java中的枚举。优势是什么?

21

将Java中的枚举定义为类与C/C++中仅作为常量集合的枚举相比,有哪些优点?


请查看https://dev59.com/hHM_5IYBdhLWcg3wWRkF#1419849。 - Narayan
10个回答

30

你可以免费获得编译时检查的有效值。使用

public static int OPTION_ONE = 0;
public static int OPTION_TWO = 1;

不能保证

void selectOption(int option) {
...
}

这将仅接受0或1作为参数值。使用枚举可以保证此功能。此外,这会导致更具自我记录性的代码,因为您可以使用代码完成功能查看所有枚举值。


10

类型安全是一个原因。

另一个,我认为更为重要的,是你可以在Java中为枚举值附加元数据。例如,你可以使用枚举来定义webservice的合法操作集,然后附加请求类型和数据类的元数据:

AddItem(HttpMethod.POST, ProductEntry.class),

3
要小心这个。我经常看到人们使用带有属性的枚举而不是类。这可能会导致周围使用枚举的代码非常奇怪和静态(实际上是试图将对象注入枚举),因为他们非常热衷于保留枚举,而不是将该枚举转换为适当的类并进行重构。 - DaveC
1
那似乎相当病态;我想看一个例子。因此,也许需要一些规则:没有可变状态,也没有行为。 - kdgregory

7
Java 5枚举类型源于Joshua BlochEffective Java(第一版)中的类型安全枚举模式,旨在避免C/C++/C#中枚举类型(只是伪装成int常量)以及Java中使用final static int常量所带来的缺陷。

主要问题在于int常量和int枚举类型不是类型安全的。可以传递任何int值。在C/C++中,可以这样做:

enum A { one, two, three };
enum B { beef, chicken, pork } b = beef;

void func(A a) { ... }
func((A)b);

很遗憾,Effective Java中的类型安全枚举模式存在大量样板代码,其中并不是所有的都很明显。最值得注意的是,你必须覆盖私有方法readResolve来阻止Java在反序列化时创建新实例,否则会破坏简单的引用检查(即使用==运算符而不是equals())。
因此,Java 5的枚举比int具有以下优势:
  • 类型安全;
  • Java 5的枚举可以具有行为和实现接口;
  • Java 5的枚举具有一些非常轻量级的数据结构,如EnumSet和EnumMap。
Java 5的枚举相对于仅使用类具有以下优势:
  • 较少出错的样板代码(私有构造函数、readResolve()等);
  • 语义正确性。你看到某个东西是枚举,就知道它只是表示一个值。你看到一个类,就不确定。也许有一个静态工厂方法之类的东西。Java 5的枚举更清晰地表明了意图。

覆盖readResolve()不是什么大问题。对于有限数量实例的类,我经常这样做。有时,枚举可以简化这些类的定义,有时则不然。用正确的工具来完成工作。 - finnw

5

除了更好的类型安全性,你还可以在枚举中定义自定义行为(请参考Effective Java获取一些好的例子)。


4

枚举类型在Java中已经是一个class

如果你想知道这为什么更好,我会说更好的类型安全性和除了简单的序数值之外添加其他属性的能力会让人想起。


2
你可以使用枚举类型有效地实现单例模式 ^^:
public enum Elvis {
    INSTANCE
}

1
-1 - 你应该避免使用单例模式,而不是寻找“有效实现”它们的方法(顺便说一句,这种方法会在加载时初始化,非常难以调试)。 - kdgregory
1
我只是想指出,如果您需要/想要使用单例模式,在Java中这是最好的方法。 - helpermethod
9
顺便提一下,单例确实有它们的用处。 - helpermethod
5
即使回答指向一个边缘情况,只要它与问题相关,我会给予+1的评价。在我看来,因为答案违背了某人的个人意识形态而投反对票是很无聊的。 - GravityWell

1

将枚举作为引用类型,可以包含一组固定的常量,这导致了高效的Map实现,例如EnumMapSet实现,例如EnumSet(JDK类)。

从EnumMap的javadoc中:
专门为枚举类型键设计的Map实现。在创建映射时,所有枚举映射中的键都必须来自指定的单个枚举类型,该类型明确或隐式地指定。枚举映射在内部表示为数组。此表示非常紧凑和高效。

EnumMap将Map的丰富性和类型安全性与数组的速度相结合(Effective Java)。


0

枚举是一种独立的类型 - 你不能使用不存在的枚举,或者放入其他类似的常量。此外,你可以对它们进行枚举,以使代码更加简洁。

使用静态常量可能会导致维护上的噩梦 - 特别是如果它们分散在各处。


0

唯一的真正优势是它可以在switch语句中使用。枚举能够完成的所有其他事情都可以使用普通的类来完成,该类具有私有构造函数,其实例反过来被声明为该类的public static final字段(类型安全模式)。枚举的另一个优点显然是它使代码比使用普通类更简洁。

但是,如果我没有记错,在C++(或者是C#?)中,您可以在switch语句中使用String。因此,与C ++相比,Java中枚举的这种优势微不足道。但是,同样的事情也被提议用于Java 7,不确定是否会实现。


0
使用枚举的好处: 可以创建一个对象,使其以与枚举相同的方式工作。事实上,在Java语言中,枚举甚至直到5.0版本才被包含进来。然而,枚举使代码更易读,并提供了更少的程序员错误空间。
引用: 《OCA Java SE 7程序员I学习指南》

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