一尘不染

比较Java枚举成员:==或equals()?

java

我知道Java枚举被编译为具有私有构造函数和一堆公共静态成员的类。比较给定枚举的两个成员时,我一直使用.equals(),例如

public useEnums(SomeEnum a)
{
    if(a.equals(SomeEnum.SOME_ENUM_VALUE))
    {
        ...
    }
    ...
}

但是,我刚遇到一些使用equals运算符==而不是.equals()的代码:

public useEnums2(SomeEnum a)
{
    if(a == SomeEnum.SOME_ENUM_VALUE)
    {
        ...
    }
    ...
}

我应该使用哪个运算符?


阅读 459

收藏
2020-03-08

共2个答案

一尘不染

两者在技术上都是正确的。如果你查看源代码.equals(),它只是顺应了==

我使用==,但是,这将是null安全的。

2020-03-08
一尘不染

可以==使用enum吗?

是的:枚举具有严格的实例控件,可==用于比较实例。这是语言规范提供的保证(我强调):

JLS 8.9枚举
枚举类型除了由其枚举常量定义的实例外,没有其他实例。

尝试显式实例化枚举类型是编译时错误。中的final clone方法Enum确保enum永远不会克隆常量,并且序列化机制的特殊处理确保了绝不会由于反序列化而创建重复的实例。禁止枚举类型的反射实例化。结合在一起,这四件事确保了enum除了enum常量定义的实例之外,不存在任何类型的实例。

因为只有一个每个实例enum常数,它允许使用的==操作者代替的equals比较两个对象的引用时,如果已知它们中的至少一个是指方法enum常数。(中的equals方法Enumfinal仅调用super.equals其参数并返回结果,从而执行身份比较的方法。)

Josh Bloch建议的这种保证足够强大,如果你坚持使用单例模式,则实现它的最佳方法是使用单元素enum(请参阅:Effective Java 2nd Edition,第3项:使用私有构造函数或枚举类型;也包括Singleton中的线程安全性)

==和之间有什么区别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.equals(b)if和onlyif a==b。如果一个类保证了这一点,那么它的客户可以使用==运算符而不是equals(Object)方法,这可能会提高性能。枚举类型提供了这种保证。

总而言之,使用==on 的参数为enum:

  • It works.
  • It’s faster.
  • It’s safer at run-time.
  • It’s safer at compile-time.
2020-03-08