java枚举赋值 - java注解枚举




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

==可以用于enum

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

JLS 8.9枚举

一个枚举类型除了由枚举常量定义的枚举类型之外没有其他实例。

尝试显式实例化枚举类型是编译时错误。 Enumfinal clone方法确保enum常量永远不会被克隆,序列化机制的特殊处理确保重复实例永远不会因反序列化而被创建。 禁止枚举类型的反射实例化。 总而言之,这四件事确保enum类型的实例不会超出enum常量定义的实例。

因为每个enum只有一个实例是常量, 所以当比较两个对象引用时,如果知道至少其中一个引用了enum常量, 则允许使用==运算符代替equals方法 。 ( Enumequals方法是一个final方法,它只是在其参数上调用super.equals并返回结果,从而执行标识比较。)

这种保证足够强大,以至于Josh Bloch建议,如果你坚持使用单例模式,实现它的最好方法是使用单元素enum (请参阅: Effective Java第2版,第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)当且仅当a==b 。 如果一个类做出这种保证,那么它的客户可以使用==运算符而不是equals(Object)方法,这可能会提高性能。 枚举类型提供了这种保证。

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

  • 有用。
  • 速度更快。
  • 运行时更安全。
  • 编译时更安全。

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

我应该使用哪一个操作符?


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

然而,我使用== ,因为那将是无效的。


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

在附注中,如果你写下如下的equals() ,实际上不需要使用==来编写null安全代码:

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

这是一个最佳做法,称为比较左边的常数 ,你绝对应该遵循。


使用除==之外的任何东西来比较枚举常量是无稽之谈。 这就像比较class对象与equals - 不要这样做!

但是,Sun JDK 6u10及更早版本中存在一个令人讨厌的bug( 6277781 ),可能因历史原因而感兴趣。 这个错误阻止了在反序列化的枚举上正确使用== ,尽管这可以说是某种角落的情况。


在枚举的情况下,两个都是正确的,正确的!


总之,两者都有优点和缺点。

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

另一方面,如果你出于任何原因用另一种方法(普通类实例)替换枚举,那么使用==咬你。 (BTDT)。


我想明确地强调==运算符和equals()方法之间的这种特定区别:

equals()方法用于检查对象引用的引用变量的内容是否相同。

==运算符检查涉及的引用变量是否引用同一个对象

实施课程由应用程序根据需要提供这种差异。

否则,默认行为将由Object类(Java中)提供,如http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#equals(java.lang.Object)

Object类的equals方法实现Object上最可能的等价关系; 也就是说,对于任何非空引用值xy ,当且仅当xy引用同一对象( x == y的值为true )时,此方法返回true


我想补充polygenelubricants答案:

我个人更喜欢equals()。 但它湖型的兼容性检查。 我认为这是一个重要的限制。

要在编译时进行类型兼容性检查,请在枚举中声明并使用自定义函数。

public boolean isEquals(enumVariable) // compare constant from left
public static boolean areEqual(enumVariable, enumVariable2) // compare two variable

有了这个,你就可以获得这两种解决方案的所有优点:NPE保护,在编译时易于阅读代码和类型兼容性检查。

我也建议为枚举添加一个UNDEFINED值。


枚举类是为public static final field (immutable)声明的每个枚举常量返回一个实例(如单例),以便可以使用==运算符来检查它们的相等性,而不是使用equals()方法


正如其他人所说,在大多数情况下, ==.equals()工作。 编译时的确定性,你没有比较其他人指出的完全不同类型的对象是有效和有益的,但是FindBugs也可以找到比较两种不同编译时类型对象的特定类型的bug(可能是Eclipse / IntelliJ编译时间检查),所以Java编译器发现它并不会增加额外的安全性。

然而:

  1. ==从来没有抛出NPE的事实是==缺点 。 几乎不需要enum类型为null ,因为您可能想要通过null表示的任何额外状态都可以作为附加实例添加到enum中。 如果它意外为null ,我宁愿有一个NPE而不是==默默评估为false。 所以我不同意它在运行时的意见是更安全的 ; 最好不要让enum值为@Nullable
  2. == 更快的论点也是假的。 在大多数情况下,您会在编译时类型为enum类的变量上调用.equals() ,在这种情况下,编译器可以知道这与==相同(因为enumequals()方法可以不被覆盖)并且可以优化功能呼叫。 我不确定编译器目前是否这样做,但如果不这样做,并且总体上是Java性能问题,那么我宁愿修复编译器,也不愿意让100,000个Java程序员改变他们的编程风格以适应一个特定的编译器版本的性能特征。
  3. enums是对象。 对于所有其他对象类型,标准比较是.equals() ,而不是== 。 我认为对enums进行例外是很危险的,因为您最终会意外地将对象与==而不是equals()相比较,特别是如果您将enum重构为非枚举类。 在这种重构的情况下,上面的工作点是错误的。 要说服你自己使用==是正确的,你需要检查有问题的值是一个enum还是一个原语; 如果它是一个非enum类,那就错了,但很容易错过,因为代码仍然会编译。 当使用.equals()会出错时,唯一的情况是所讨论的值是基元; 在那种情况下,代码不会编译,所以很难错过。 因此, .equals()更容易识别为正确的,并且对未来的重构更安全。

我实际上认为Java语言应该已经在Object上定义了==来调用左侧值的.equals(),并且为对象标识引入了一个单独的运算符,但这不是Java定义的方式。

总之,我仍然认为参数赞成使用enum类型的.equals()







enums