协慌网

登录 贡献 社区

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

我知道 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()的源代码,它只是推迟到==

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

可以==enum上使用吗?

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

JLS 8.9 枚举

枚举类型没有除其枚举常量定义的实例之外的实例。

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

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

这种保证足够强大,Josh Bloch 建议,如果你坚持使用单例模式,实现它的最好方法是使用单元素enum (参见: Effective Java 2nd Edition,Item 3:Enforce the singleton property with 私有构造函数或枚举类型 ; 还有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上使用==的参数是:

  • 有用。
  • 它更快。
  • 它在运行时更安全。
  • 它在编译时更安全。

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

另外,如果你像这样编写equals() ,实际上不需要使用==来编写 null 安全代码:

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

这是一种称为 “ 从左边比较常量”的最佳实践,你绝对应该遵循。