可以在 Java 中的枚举上使用 == 吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/533922/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:55:41  来源:igfitidea点击:

Is it OK to use == on enums in Java?

javasyntaxenums

提问by Kip

Is it OK to use ==on enums in Java, or do I need to use .equals()? In my testing, ==always works, but I'm not sure if I'm guaranteed of that. In particular, there is no .clone()method on an enum, so I don't know if it is possible to get an enum for which .equals()would return a different value than ==.

可以==在 Java 中使用枚举,还是我需要使用.equals()?在我的测试中,==总是有效,但我不确定我是否能保证这一点。特别是,.clone()枚举没有方法,所以我不知道是否有可能获得一个枚举,其.equals()返回的值与==.

For example, is this OK:

例如,这可以吗:

public int round(RoundingMode roundingMode) {
  if(roundingMode == RoundingMode.HALF_UP) {
    //do something
  } else if (roundingMode == RoundingMode.HALF_EVEN) {
    //do something
  }
  //etc
}

Or do I need to write it this way:

还是我需要这样写:

public int round(RoundingMode roundingMode) {
  if(roundingMode.equals(RoundingMode.HALF_UP)) {
    //do something
  } else if (roundingMode.equals(RoundingMode.HALF_EVEN)) {
    //do something
  }
  //etc
}

采纳答案by Varkhan

Just my 2 cents: Here is the code for Enum.java, as published by Sun, and part of the JDK:

只需我的 2 美分:这是 Sun 发布的 Enum.java 代码和 JDK 的一部分:

public abstract class Enum<E extends Enum<E>>
    implements Comparable<E>, Serializable {

    // [...]

    /**
     * Returns true if the specified object is equal to this
     * enum constant.
     *
     * @param other the object to be compared for equality with this object.
     * @return  true if the specified object is equal to this
     *          enum constant.
     */
    public final boolean equals(Object other) { 
        return this==other;
    }


}

回答by Jon Skeet

Yes, == is fine - there's guaranteed to be just a single reference for each value.

是的, == 很好 - 保证每个值只有一个引用。

However, there's a better way of writing your round method:

但是,有一种更好的方法来编写您的圆形方法:

public int round(RoundingMode roundingMode) {
  switch (roundingMode) {
    case HALF_UP:
       //do something
       break;
    case HALF_EVEN:
       //do something
       break;
    // etc
  }
}

An even betterway of doing it is to put the functionality within the enum itself, so you could just call roundingMode.round(someValue). This gets to the heart of Java enums - they're object-orientedenums, unlike the "named values" found elsewhere.

一个更好的方法是将功能放在枚举本身中,这样你就可以调用roundingMode.round(someValue). 这是 Java 枚举的核心——它们是面向对象的枚举,与其他地方的“命名值”不同。

EDIT: The spec isn't very clear, but section 8.9states:

编辑:规范不是很清楚,但第 8.9 节指出:

The body of an enum type may contain enum constants. An enum constant defines an instance of the enum type. An enum type has no instances other than those defined by its enum constants.

枚举类型的主体可能包含枚举常量。枚举常量定义了枚举类型的一个实例。除了由其枚举常量定义的实例之外,枚举类型没有其他实例。

回答by levand

== compares the references of two objects. For enums, it is guaranteed that there will only be one instance, and therefore for any two enums that are the same, == will be true.

== 比较两个对象的引用。对于枚举,保证只有一个实例,因此对于任何两个相同的枚举,== 将为真。

Reference:

参考:

http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks

http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks

(couldn't find anything in the Sun docs)

(在 Sun 文档中找不到任何内容)

回答by Peter Lawrey

Here is some evil code you might find interesting. :D

这里有一些你可能会感兴趣的邪恶代码。:D

public enum YesNo {YES, NO}

public static void main(String... args) throws Exception {
    Field field = Unsafe.class.getDeclaredField("theUnsafe");
    field.setAccessible(true);
    Unsafe unsafe = (Unsafe) field.get(null);
    YesNo yesNo = (YesNo) unsafe.allocateInstance(YesNo.class);

    Field name = Enum.class.getDeclaredField("name");
    name.setAccessible(true);
    name.set(yesNo, "YES");

    Field ordinal = Enum.class.getDeclaredField("ordinal");
    ordinal.setAccessible(true);
    ordinal.set(yesNo, 0);

    System.out.println("yesNo " + yesNo);
    System.out.println("YesNo.YES.name().equals(yesNo.name()) "+YesNo.YES.name().equals(yesNo.name()));
    System.out.println("YesNo.YES.ordinal() == yesNo.ordinal() "+(YesNo.YES.ordinal() == yesNo.ordinal()));
    System.out.println("YesNo.YES.equals(yesNo) "+YesNo.YES.equals(yesNo));
    System.out.println("YesNo.YES == yesNo " + (YesNo.YES == yesNo));
}

回答by Dilum Ranatunga

Yes, it is as if you had created singleton instances for each value in the enum:

是的,就好像您为枚举中的每个值创建了单例实例:

public abstract class RoundingMode {
  public static final RoundingMode HALF_UP = new RoundingMode();
  public static final RoundingMode HALF_EVEN = new RoundingMode();

  private RoundingMode() {
    // private scope prevents any subtypes outside of this class
  }
}

However, the enumconstruct gives you various benefits:

但是,该enum构造为您提供了多种好处:

  • Each instance's toString() prints the name given in code.
  • (As mentioned in another post,) a variable of the enum type can be compared against constants using the switch-casecontrol structure.
  • All the values in the enumeration can be queried using the valuesfield that is 'generated' for each enum type
  • Here's the big one w.r.t identity comparisons:enum values survive serialization without cloning.
  • 每个实例的 toString() 打印代码中给出的名称。
  • (如另一篇文章所述,)可以使用switch-case控制结构将枚举类型的变量与常量进行比较。
  • 可以使用values为每个枚举类型“生成”的字段查询枚举中的所有值
  • 这是身份比较的重要内容:枚举值无需克隆即可在序列化中幸存下来。

The serialization is a big gotchya. If I were to use the code above instead of an enum, here's how identity equality would behave:

序列化是一个大问题。如果我使用上面的代码而不是枚举,则身份相等的行为方式如下:

RoundingMode original = RoundingMode.HALF_UP;
assert (RoundingMode.HALF_UP == original); // passes

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(original);
oos.flush();

ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
RoundingMode deserialized = (RoundingMode) ois.readObject();

assert (RoundingMode.HALF_UP == deserialized); // fails
assert (RoundingMode.HALF_EVEN == deserialized); // fails

You canaddress this issue without enum, using a technique that involves writeReplaceand readResolve, (see http://java.sun.com/j2se/1.4.2/docs/api/java/io/Serializable.html)...

可以在不使用枚举的情况下使用涉及writeReplace和的技术解决此问题readResolve(请参阅http://java.sun.com/j2se/1.4.2/docs/api/java/io/Serializable.html)...

I guess the point is -- Java goes out of its way to allow you use enum values' identities for testing equality; it is an encouraged practice.

我想重点是——Java 不遗余力地允许您使用枚举值的身份来测试相等性;这是一种鼓励的做法。

回答by paulmurray

Enums are a great place to jam polymorphic code.

枚举是阻塞多态代码的好地方。

enum Rounding {
  ROUND_UP {
    public int round(double n) { ...; }
  },
  ROUND_DOWN {
    public int round(double n) { ...; }
  };

  public abstract int round(double n);
}

int foo(Rounding roundMethod) {
  return roundMethod.round(someCalculation());
}

int bar() {
  return foo(Rounding.ROUND_UP);
}

回答by paulmurray

Note that there is problem when transfering enum via RMI/IIOP. See this thread:

请注意,通过 RMI/IIOP 传输枚举时存在问题。看到这个线程:

http://www.velocityreviews.com/forums/t390342-enum-equality.html

http://www.velocityreviews.com/forums/t390342-enum-equality.html

回答by Tobias

== is generally okay, and there are advantages to both == and .equals(). I personally prefer to always use .equals()when comparing Objects, including enums. See also this discussion:

== 通常是可以的,并且 == 和.equals(). 我个人更喜欢.equals()在比较对象时总是使用,包括enums。另见此讨论:

Comparing Java enum members: == or equals()?

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