我知道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)
    {
        ...
    }
    ...
}

我应该使用哪个操作员?


当前回答

enums容易与==一起工作的原因是每个定义的实例也是一个单实例。因此,使用==进行身份比较总是有效的。

但使用==,因为它与枚举一起使用,意味着所有代码都与该枚举的使用紧密耦合。

例如:枚举可以实现接口。假设您当前正在使用实现Interface1的枚举。若稍后,有人将其更改或引入一个新的类Impl1作为同一接口的实现。然后,如果您开始使用Impl1的实例,由于前面使用了==,您将有很多代码需要更改和测试。

因此,除非有任何正当利益,否则最好遵循被视为良好的做法。

其他回答

简而言之,两者都有利弊。

一方面,如其他答案所述,使用==具有优势。

另一方面,如果出于任何原因使用不同的方法(普通类实例)替换enum,那么使用==会使您受到攻击。(待定)

enums容易与==一起工作的原因是每个定义的实例也是一个单实例。因此,使用==进行身份比较总是有效的。

但使用==,因为它与枚举一起使用,意味着所有代码都与该枚举的使用紧密耦合。

例如:枚举可以实现接口。假设您当前正在使用实现Interface1的枚举。若稍后,有人将其更改或引入一个新的类Impl1作为同一接口的实现。然后,如果您开始使用Impl1的实例,由于前面使用了==,您将有很多代码需要更改和测试。

因此,除非有任何正当利益,否则最好遵循被视为良好的做法。

tl;博士

另一个选项是Objects.equals实用程序方法。

Objects.equals( thisEnum , thatEnum )

Objects.equals表示空安全

equals运算符==而不是.equals()

我应该使用哪个操作员?

第三个选项是添加到Java7和更高版本的Objects实用程序类中的static equals方法。

实例

下面是使用Month枚举的示例。

boolean areEqual = Objects.equals( Month.FEBRUARY , Month.JUNE ) ;  // Returns `false`.

福利

我发现这种方法有几个好处:

零安全性两者均为空➙ 真的要么为空➙ 假的没有引发NullPointerException的风险紧凑、可读

它的工作原理

Objects.equals使用的逻辑是什么?

请自行查看OpenJDK的Java 10源代码:

return 
    ( a == b ) 
    || 
    ( 
        a != null 
        && 
        a.equals( b )
    )
;

可以在枚举上使用==吗?

是:enum具有严格的实例控件,允许您使用==来比较实例。以下是语言规范提供的保证(由我强调):

JLS 8.9枚举枚举类型除了由其枚举常量定义的实例之外,没有其他实例。尝试显式实例化枚举类型是一个编译时错误。Enum中的最后一个clone方法确保永远无法克隆枚举常量,序列化机制的特殊处理确保永远不会由于反序列化而创建重复实例。禁止枚举类型的反射实例化。这四点共同确保了枚举类型的实例不存在于枚举常量定义的实例之外。因为每个枚举常量只有一个实例,所以在比较两个对象引用时,如果已知其中至少一个引用了枚举常量,则允许使用==运算符代替equals方法。(Enum中的equals方法是一个最终方法,它只在其参数上调用super.equals并返回结果,从而执行身份比较。)

乔什·布洛克(Josh Bloch)建议,如果您坚持使用单例模式,最好的实现方法是使用单个元素枚举(请参阅:有效的Java第二版,第3项:使用私有构造函数或枚举类型强制执行单例属性;另请参阅singleton中的线程安全)


==和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)当且仅当a==b。如果类提供了这种保证,那么它的客户端可以使用==运算符而不是equals(Object)方法,这可能会提高性能。枚举类型提供了这种保证。

总而言之,在enum上使用==的参数如下:

它起作用了。速度更快。运行时更安全。编译时更安全。

只有一件事可以补充所有其他优秀的答案。当您使用简单的lambda时,我更喜欢等于而不是==,因为您可以使用方法引用。

考虑以下lambdas:

Stream.of(SomeEnum.A, SomeEnum.B).anyMatch(e -> e == SomeEnum.B);
Stream.of(SomeEnum.A, SomeEnum.B).anyMatch(e -> e.equals(SomeEnum.B));

后者可以转换为:

Stream.of(SomeEnum.A, SomeEnum.B).anyMatch(SomeEnum.B::equals));