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

我应该使用哪个操作员?


当前回答

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

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

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

其他回答

使用==以外的任何方法来比较枚举常量都是无稽之谈。这就像将类对象与equals进行比较——不要这样做!

然而,由于历史原因,Sun JDK 6u10和更早版本中存在一个令人讨厌的bug(BugId 6277781)。这个错误阻止了在反序列化的枚举上正确使用==,尽管这可以说是一种极端情况。

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

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

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

使用==比较两个枚举值是有效的,因为每个枚举常量只有一个对象。

另一方面,如果您像这样编写equals(),实际上不需要使用==来编写空安全代码:

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

这是一个被称为“从左侧比较常量”的最佳实践,您绝对应该遵循。

下面是一个粗略的时间测试,以比较两者:

import java.util.Date;

public class EnumCompareSpeedTest {

    static enum TestEnum {ONE, TWO, THREE }

    public static void main(String [] args) {

        Date before = new Date();
        int c = 0;

        for(int y=0;y<5;++y) {
            for(int x=0;x<Integer.MAX_VALUE;++x) {
                if(TestEnum.ONE.equals(TestEnum.TWO)) {++c;}
                if(TestEnum.ONE == TestEnum.TWO){++c;}              
            }
        }

        System.out.println(new Date().getTime() - before.getTime());
    }   

}

一次评论一个国际单项体育联合会。以下是上面两个比较的分解字节码:

 21  getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
 24  getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
 27  invokevirtual EnumCompareSpeedTest$TestEnum.equals(java.lang.Object) : boolean [28]
 30  ifeq 36

 36  getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
 39  getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
 42  if_acmpne 48

第一个(equals)执行虚拟调用并测试堆栈中的返回布尔值。第二个(==)比较直接来自堆栈的对象地址。在第一种情况下,有更多的活动。

我对两个国际单项体育联合会一次进行了几次测试。“==”速度稍快。

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 )
    )
;