web-dev-qa-db-ja.com

Javaの列挙型で==を使用しても大丈夫ですか?

Javaの列挙型で==を使用しても大丈夫ですか、それとも.equals()を使用する必要がありますか?私のテストでは、==は常に動作しますが、それが保証されているかどうかはわかりません。特に、enumには.clone()メソッドがないため、.equals()==と異なる値を返す列挙型を取得できるかどうかわかりません。

たとえば、これはOKですか:

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

ちょうど私の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;
    }


}
145
Varkhan

はい、==で問題ありません-各値に対してただ1つの参照が保証されます。

ただし、ラウンドメソッドを記述するより良い方法があります。

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

偶数betterの方法は、enum内に機能を配置することです。したがって、単にroundingMode.round(someValue)を呼び出すことができます。これは、Java列挙型-それらはオブジェクト指向の列挙型であり、「名前付き値」とは異なります)他の場所で見つかりました。

編集:仕様はあまり明確ではありませんが、 セクション8.9 の状態:

列挙型の本体には、列挙定数が含まれる場合があります。列挙定数は、列挙型のインスタンスを定義します。列挙型には、その列挙定数で定義されたもの以外のインスタンスはありません。

76
Jon Skeet

はい、enumの各値に対してシングルトンインスタンスを作成した場合と同じです。

 public abstract class RoundingMode {
 public static final RoundingMode HALF_UP = new RoundingMode(); 
 public static final RoundingMode HALF_EVEN = new RoundingMode(); 
 
 private RoundingMode(){
 //プライベートスコープは、このクラス
} 
} 
外のサブタイプを防止します

しかしながらenumコンストラクトにはさまざまな利点があります。

  • 各インスタンスのtoString()は、コードで指定された名前を出力します。
  • (別の投稿で述べたように)列挙型の変数は、switch-case制御構造を使用して定数と比較できます。
  • 列挙型のすべての値は、各列挙型に対して「生成された」valuesフィールドを使用して照会できます。
  • 以下は、IDの比較を行う大きなものです。 列挙値は、クローンを作成せずにシリアル化されます。

シリアル化は大きな問題です。列挙型の代わりに上記のコードを使用する場合、同一性の等価性は次のようになります。

 RoundingMode original = RoundingMode.HALF_UP; 
 assert(RoundingMode.HALF_UP == original); // pass 
 
 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); //失敗します
 assert(RoundingMode.HALF_EVEN == deserialized); //失敗します

君は できる writeReplacereadResolveを含む手法を使用して、enumなしでこの問題に対処します( http://Java.Sun.com/j2se/1.4.2/docs/apiを参照/Java/io/Serializable.html )...

重要な点は、-Javaは、等しいかどうかをテストするために列挙値のIDを使用できるようになり、推奨される方法です。

13
Dilum Ranatunga

== 2つのオブジェクトの参照を比較します。列挙型の場合、インスタンスは1つだけであることが保証されているため、同じ2つの列挙型の場合、==はtrueになります。

参照:

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

(Sunのドキュメントには何も見つかりませんでした)

10
levand

ここにあなたが面白いと思うかもしれないいくつかの邪悪なコードがあります。 :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));
}
6
Peter Lawrey

列挙型は、多態性コードを詰め込むのに最適な場所です。

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

RMI/IIOPを介してenumを転送する場合、問題があることに注意してください。このスレッドを参照してください:

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

1
johny

==は通常大丈夫で、==と.equals()の両方に利点があります。個人的には、enumsを含むオブジェクトを比較するときに、常に.equals()を使用することを好みます。この議論も参照してください。

比較Java enumメンバ:== or equals()?

1
Tobias