我知道 Java 枚举被编译为具有私有构造函数和一堆公共静态成员的类。在比较给定枚举的两个成员时,我一直使用.equals(),例如
.equals()
public useEnums(SomeEnum a) { if(a.equals(SomeEnum.SOME_ENUM_VALUE)) { ... } ... }
但是,我刚刚遇到了一些使用 equals 运算符==而不是 .equals() 的代码:
==
public useEnums2(SomeEnum a) { if(a == SomeEnum.SOME_ENUM_VALUE) { ... } ... }
我应该使用哪个运算符?
两者在技术上都是正确的。如果您查看 的源代码.equals(),它只是遵循==.
但是,我使用==,因为这将是 null 安全的。
是的:枚举具有严格的实例控制,允许您用来==比较实例。这是语言规范提供的保证(我强调):
JLS 8.9 枚举 枚举类型除了由其枚举常量定义的实例外,没有其他实例。 尝试显式实例化枚举类型是编译时错误。中的final clone方法Enum确保enum永远不会克隆常量,并且序列化机制的特殊处理确保永远不会由于反序列化而创建重复的实例。禁止枚举类型的反射实例化。这四件事一起确保不enum存在超出enum常量定义的类型的实例。 enum因为每个常量只有一个实例,所以在比较两个对象引用时,如果知道其中至少一个引用了一个***常量,则允许使用==运算符代替equals``enum*方法。(equalsin中的方法Enum是一个final仅调用super.equals其参数并返回结果的方法,从而执行身份比较。)
枚举类型除了由其枚举常量定义的实例外,没有其他实例。
尝试显式实例化枚举类型是编译时错误。中的final clone方法Enum确保enum永远不会克隆常量,并且序列化机制的特殊处理确保永远不会由于反序列化而创建重复的实例。禁止枚举类型的反射实例化。这四件事一起确保不enum存在超出enum常量定义的类型的实例。
final clone
Enum
enum
enum因为每个常量只有一个实例,所以在比较两个对象引用时,如果知道其中至少一个引用了一个***常量,则允许使用==运算符代替equals``enum*方法。(equalsin中的方法Enum是一个final仅调用super.equals其参数并返回结果的方法,从而执行身份比较。)
equals``enum
equals
final
super.equals
这个保证足够强大,Josh Bloch 建议,如果您坚持使用单例模式,实现它的最佳方式是使用单元素enum(请参阅:Effective Java 2nd Edition,第 3 项:使用私有构造函数或枚举类型;也是Singleton 中的线程安全)
提醒一下,需要说的是,通常==不是equals. 但是,当它是(例如 with 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.equals(b)当且仅当a==b. 如果一个类做了这个保证,那么它的客户可以使用==操作符而不是equals(Object)方法,这可能会导致性能的提高。枚举类型提供了这种保证。
第 1 项:考虑静态工厂方法而不是构造函数
[…] 它允许不可变类保证不存在两个相等的实例:a.equals(b)当且仅当a==b. 如果一个类做了这个保证,那么它的客户可以使用==操作符而不是equals(Object)方法,这可能会导致性能的提高。枚举类型提供了这种保证。
a.equals(b)
a==b
equals(Object)
总而言之,使用==on的论点enum是: