比较Java中的枚举成员:使用==还是equals()?
比较Java中的枚举成员:使用==还是equals()?
我知道Java枚举被编译成具有私有构造函数和许多公共静态成员变量的类。在比较给定枚举的两个成员时,我通常使用.equals()
,例如:
public useEnums(SomeEnum a) { if(a.equals(SomeEnum.SOME_ENUM_VALUE)) { ... } ... }
然而,我刚刚看到一些使用等于运算符==
而不是.equals()的代码:
public useEnums2(SomeEnum a) { if(a == SomeEnum.SOME_ENUM_VALUE) { ... } ... }
我应该使用哪个运算符?
枚举类型可以使用 ==
吗?
可以:枚举类型具有严格的实例控制,允许您使用 ==
比较实例。以下是语言规范提供的保证(我强调的部分):
JLS 8.9 枚举类型
除了由其枚举常量定义的实例之外,枚举类型没有其他实例。
在尝试显式实例化枚举类型时,会产生编译时错误。在
Enum
中的final clone
方法确保enum
常量永远无法被克隆,并且序列化机制的特殊处理确保不会因反序列化而创建重复实例。禁止反射实例化枚举类型。这四件事情共同确保不存在除由枚举常量定义的实例之外的任何enum
实例。由于每个
enum
常量只有一个实例,如果已知其中至少一个引用了一个enum
常量,可以在比较两个对象引用时使用==
运算符替代equals
方法。(Enum
中的equals
方法是一个final
方法,它只在其参数上调用super.equals
并返回结果,从而执行身份比较。)
这种保证足够强大,以至于Josh Bloch建议,如果您坚持使用单例模式,则最好的实现方式是使用一个单元素的 enum
(请参见:Effective Java 2nd Edition,第3项:使用私有构造函数或枚举类型强制执行单例属性;还可以查看 单例模式中的线程安全)
“==”和“equals”有什么区别?
需要提醒的是,通常来讲,“==”不是“equals”的替代品。然而,在某些情况下,例如使用enum
时,“==”可以作为可行的替代方法。但是,需要考虑两个重要的差别:
“==”永远不会抛出NullPointerException
enum Color { BLACK, WHITE }; Color nothing = null; if (nothing == Color.BLACK); // runs fine if (nothing.equals(Color.BLACK)); // throws NullPointerException
“==”在编译时受到类型兼容性检查的影响
enum Color { BLACK, WHITE }; enum Chiral { LEFT, RIGHT }; if (Color.BLACK.equals(Chiral.LEFT)); // compiles fine if (Color.BLACK == Chiral.LEFT); // DOESN'T COMPILE!!! Incompatible types!
适用情况下是否应该使用“==”?
Bloch特别提到,具有正确的实例控制的不可变类可以向其客户端保证“==”是可用的。enum
被特别提到作为示例。
条款1:考虑使用静态工厂方法代替构造器
……它使得一个不可变的类可以保证不存在两个相等的实例:当且仅当
a==b
时才会有a.equals(b)
。如果一个类做出了这样的保证,那么它的客户端可以使用“==”运算符而不是“equals(Object)”方法,这可能会提高性能。枚举类型提供这种保证。
总的来说,使用“==”来处理enum
的论点如下:
- 有效。
- 速度更快。
- 在运行时更安全。
- 在编译时更安全。