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

时间:2009-02-10 19:59:01

标签: java syntax enums

在Java中的枚举上使用==是否可以,或者我是否需要使用.equals()?在我的测试中,==始终有效,但我不确定我是否能保证这一点。特别是,枚举上没有.clone()方法,因此我不知道是否有可能获得枚举.equals()将返回与==不同的值。< / p>

例如,这样就可以了:

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

或者我需要这样写:

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

8 个答案:

答案 0 :(得分:142)

只需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;
    }


}

答案 1 :(得分:76)

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

然而,有一种更好的方法来编写圆形方法:

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

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

编辑:规范不是很清楚,但section 8.9表示:

  

枚举类型的主体可能包含   枚举常量。枚举常数   定义枚举类型的实例。   枚举类型没有其他实例   比它的枚举定义的那些   常数。

答案 2 :(得分:13)

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

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
  }
}

然而enum结构为您提供了各种好处:

  • 每个实例的toString()都会打印代码中给出的名称。
  • (如另一篇文章所述),可以使用switch-case控件结构将枚举类型的变量与常量进行比较。
  • 可以使用为每个枚举类型“生成”的values字段查询枚举中的所有值
  • 以下是w.r.t身份比较中最重要的一个:枚举值在没有克隆的情况下继续进行序列化。

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

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

可以使用涉及writeReplacereadResolve的技术(请参阅http://java.sun.com/j2se/1.4.2/docs/api/java/io/Serializable.html)而无需枚举来解决此问题...

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

答案 3 :(得分:10)

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

参考:

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

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

答案 4 :(得分:6)

这是一些你可能会感兴趣的恶意代码。 :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));
}

答案 5 :(得分:3)

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

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

答案 6 :(得分:1)

请注意,通过RMI / IIOP传输枚举时会出现问题。见这个主题:

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

答案 7 :(得分:1)

==通常没问题,并且==和.equals()都有优势。我个人更喜欢在比较对象时始终使用.equals(),包括enum。另见讨论:

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