105 votes

Peut-on utiliser == sur des enums en Java?

Est-il possible d'utiliser == sur les enums en Java, ou dois-je utiliser .equals()? Dans mes tests, == fonctionne toujours, mais je ne suis pas sûr si je suis garanti. En particulier, il n'y a pas d' .clone() méthode sur un enum, donc je ne sais pas si il est possible d'obtenir un enum pour qui .equals() doit retourner une valeur différente de celle ==.

Par exemple, est-ce OK:

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

Ou dois-je écrire de cette façon:

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

146voto

Varkhan Points 6756

Juste mes 2 cents: Voici le code pour Enum.java, tel que publié par Sun, et une partie du 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;
    }


}
 

76voto

Jon Skeet Points 692016

Oui, == est très bien - il y a la garantie d'être simplement une référence unique pour chaque valeur.

Cependant, il ya une meilleure façon d'écrire à votre tour méthode:

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

Une bien meilleure façon de le faire est de mettre de la fonctionnalité au sein de l'enum lui-même, de sorte que vous pouvez simplement appeler roundingMode.round(someValue). C'est au cœur de Java enums - ils orienté objet enums, à la différence des "valeurs" trouvés ailleurs.

EDIT: La spec n'est pas très clair, mais l'article 8.9 états:

Le corps d'un type enum peut contenir enum constantes. Une constante enum définit une instance de type enum. Un type enum n'a pas d'autres instances que ceux définis par ses enum les constantes.

13voto

Dilum Ranatunga Points 7677

Oui, c'est comme si vous aviez créé singleton instances pour chaque valeur de l'enum:

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

 privé RoundingMode() {
 // portée privée empêche tout sous-dehors de cette classe
}
}

Cependant, l' enum construction vous offre divers avantages:

  • Chaque instance de toString() affiche le nom donné dans le code.
  • (Comme mentionné dans un autre post, une variable de type enum peut être comparé à des constantes à l'aide de l' switch-case de la structure de contrôle.
  • Toutes les valeurs dans l'énumération peut être interrogé à l'aide de l' values champ qui est "générée" pour chaque type enum
  • Voici le grand w.r.t de l'identité des comparaisons: les valeurs de l'enum survivre à la sérialisation sans clonage.

La sérialisation est un grand gotchya. Si je devais utiliser le code ci-dessus à la place d'un enum, voici comment l'identité des sexes se comporter:

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

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 désérialisé = (RoundingMode) ois.readObject();

assert (RoundingMode.HALF_UP == désérialisé); // échoue
assert (RoundingMode.HALF_EVEN == désérialisé); // échoue

Vous pouvez résoudre ce problème sans enum, à l'aide d'une technique qui implique l' writeReplace et readResolve (voir http://java.sun.com/j2se/1.4.2/docs/api/java/io/Serializable.html)...

Je suppose que le point est -- Java sort de sa façon de vous permettre d'utiliser les valeurs de l'enum' identités pour les tests d'égalité; c'est un encourage la pratique.

10voto

levand Points 4020

== compare les références de deux objets. Pour les énumérations, il est garanti qu’il n’y aura qu’une seule instance, et donc pour deux énumérations identiques, == sera vrai.

Référence:

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

(rien trouvé dans les documents Sun)

6voto

Peter Lawrey Points 229686

Voici un code maléfique que vous pourriez trouver intéressant. :RÉ

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X