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

我应该使用哪个操作员?


当前回答

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

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

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

其他回答

Sonar规则之一是Enum值应与“==”进行比较。原因如下:

使用equals()测试枚举值的相等性是完全有效的,因为枚举是一个Object,每个Java开发人员都知道==不应用于比较Object的内容。同时,在enums上使用==:提供与equals()相同的预期比较(内容)比equals()更安全提供编译时(静态)检查而不是运行时检查出于这些原因,应该优先使用==而不是equals()。

最后但并非最不重要的是,enums上的==可以说比equals()更可读(更不冗长)。

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

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

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

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

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

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

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

我更喜欢使用==而不是equals:

除了这里已经讨论过的其他原因之外,还有一个原因,那就是你可能会在没有意识到的情况下引入一个bug。假设你有一个完全相同的enums,但在不同的包中(这并不常见,但可能会发生):

第一个枚举:

package first.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

第二个枚举:

package second.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

然后假设您在item.category中使用了类似next的equals,即first.pckg.category,但您导入了第二个enum(second.pckkg.category),而不是第一个enum,而没有意识到它:

import second.pckg.Category;
...

Category.JAZZ.equals(item.getCategory())

因此,尽管item.getCategory()是JAZZ,但由于是一个不同的枚举,所以您将始终得到false。这可能有点难以理解。

因此,如果改用运算符==,将出现编译错误:

运算符==不能应用于“second.pkg.Category”、“first.pkg.Ccategory”

import second.pckg.Category; 
...

Category.JAZZ == item.getCategory() 

两者在技术上都是正确的。如果查看.equals()的源代码,它只需遵循==。

然而,我使用==,因为这将是空安全的。