valueof - java test enum




Vergleichen von Java-Enum-Membern:== oder equals()? (10)

Ich weiß, dass Java-Enums in Klassen mit privaten Konstruktoren und einer Reihe öffentlicher statischer Member kompiliert werden. Beim Vergleich von zwei Mitgliedern einer gegebenen Enumeration habe ich immer .equals() , z

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

Ich bin jedoch auf einen Code gestoßen, der den Gleichheitsoperator == anstelle von .equals () verwendet:

public useEnums2(SomeEnum a)
{
    if(a == SomeEnum.SOME_ENUM_VALUE)
    {
        ...
    }
    ...
}

Welcher Operator sollte ich verwenden?


Kann == enum auf enum ?

Ja: enums verfügen über strenge Instanzsteuerelemente, mit denen Sie == zum Vergleichen von Instanzen verwenden können. Hier ist die Garantie der Sprachspezifikation (Hervorhebung von mir):

JLS 8.9 Enums

Ein Aufzählungstyp hat keine anderen Instanzen als die, die durch seine Aufzählungskonstanten definiert sind.

Es ist ein Kompilierungsfehler, wenn Sie versuchen, einen Aufzählungstyp explizit zu instanziieren. Die final clone in Enum stellt sicher, dass enum Konstanten niemals geklont werden können. Die spezielle Behandlung durch den Serialisierungsmechanismus stellt sicher, dass doppelte Instanzen niemals als Ergebnis der Deserialisierung erstellt werden. Reflektierende Instanziierung von Enum-Typen ist verboten. Zusammen gewährleisten diese vier Dinge, dass keine Instanzen eines enum existieren, die über die durch die enum definierten hinausgehen.

Da es nur eine Instanz jeder enum Konstante gibt, ist es zulässig, den Operator == anstelle der Methode equals verwenden, wenn zwei Objektreferenzen verglichen werden, wenn bekannt ist, dass sich mindestens eine davon auf eine enum Konstante bezieht . (Die equals Methode in Enum ist eine final Methode, die nur super.equals für ihr Argument aufruft und das Ergebnis zurückgibt, wodurch ein Identitätsvergleich durchgeführt wird.)

Diese Garantie ist stark genug, dass Josh Bloch empfiehlt, dass, wenn Sie darauf bestehen, das Singleton-Muster zu verwenden, der beste Weg, es zu implementieren, eine Enumeration mit einem einzelnen Element ist (siehe: Effektive Java 2nd Edition, Punkt 3: Erzwingen Sie die Singleton-Eigenschaft mit ein privater Konstruktor oder ein Enum-Typ ; auch Thread-Sicherheit in Singleton )

Was sind die Unterschiede zwischen == und equals ?

Zur Erinnerung, es muss gesagt werden, dass == Allgemeinen KEINE brauchbare Alternative zu equals . Wenn es jedoch (wie mit enum ) ist, gibt es zwei wichtige Unterschiede zu beachten:

== NullPointerException niemals NullPointerException

enum Color { BLACK, WHITE };

Color nothing = null;
if (nothing == Color.BLACK);      // runs fine
if (nothing.equals(Color.BLACK)); // throws NullPointerException

== unterliegt der Typkompatibilitätsprüfung zur Kompilierzeit

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!

Sollte == werden, wenn zutreffend?

Bloch erwähnt ausdrücklich, dass unveränderliche Klassen, die eine angemessene Kontrolle über ihre Instanzen haben, ihren Clients garantieren können, dass == verwendbar ist. enum wird speziell zur Veranschaulichung erwähnt.

Punkt 1: Berücksichtigen Sie statische Factory-Methoden anstelle von Konstruktoren

[...] es erlaubt einer unveränderlichen Klasse, die Garantie zu geben, dass keine zwei gleichen Instanzen existieren: a.equals(b) genau dann, wenn a==b . Wenn eine Klasse diese Garantie übernimmt, können ihre Clients den Operator == anstelle der Methode equals(Object) verwenden, was zu einer verbesserten Leistung führen kann. Enum-Typen bieten diese Garantie.

Zusammenfassend sind die Argumente für die Verwendung von == auf enum :

  • Es klappt.
  • Es ist schneller.
  • Zur Laufzeit ist es sicherer.
  • Es ist sicherer zur Kompilierzeit.

Beide sind technisch korrekt. Wenn Sie sich den Quellcode für .equals() , wird einfach auf == .equals() .

Ich benutze jedoch == , da dies null sicher ist.


Die Verwendung von == zum Vergleichen zweier Aufzählungswerte funktioniert, da für jede Aufzählungskonstante nur ein Objekt vorhanden ist.

Nebenbei bemerkt, es besteht eigentlich keine Notwendigkeit, == zu verwenden, um einen Null-Sicherheitscode zu schreiben, wenn Sie Ihr equals() wie folgt schreiben:

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

Dies ist eine bewährte Methode, die als Constants From The Left bekannt ist und der Sie unbedingt folgen sollten.


Enum in der Mitte ist eine Menge konstanter Ganzzahlen. "==" ist genauso gültig und korrekt wie wenn Sie zwei ganze Zahlen verglichen haben.


Etwas anderes als == zu verwenden, um Enum-Konstanten zu vergleichen, ist Unsinn. Es ist, als würde man class mit equals - tu es nicht!

Allerdings gab es in Sun JDK 6u10 und früher einen Bug (BugId 6277781 ), der aus historischen Gründen interessant sein könnte. Dieser Fehler verhinderte die korrekte Verwendung von == bei deserialisierten Enums, obwohl dies wohl eher ein Eckfall ist.


Hier ist ein grober Timing-Test, um die beiden zu vergleichen:

import java.util.Date;

public class EnumCompareSpeedTest {

    static enum TestEnum {ONE, TWO, THREE }

    public static void main(String [] args) {

        Date before = new Date();
        int c = 0;

        for(int y=0;y<5;++y) {
            for(int x=0;x<Integer.MAX_VALUE;++x) {
                if(TestEnum.ONE.equals(TestEnum.TWO)) {++c;}
                if(TestEnum.ONE == TestEnum.TWO){++c;}              
            }
        }

        System.out.println(new Date().getTime() - before.getTime());
    }   

}

Kommentieren Sie die IF einzeln aus. Hier sind die zwei Vergleiche von oben in disassembliertem Byte-Code:

 21  getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
 24  getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
 27  invokevirtual EnumCompareSpeedTest$TestEnum.equals(java.lang.Object) : boolean [28]
 30  ifeq 36

 36  getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
 39  getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
 42  if_acmpne 48

Der erste (equals) führt einen virtuellen Aufruf durch und testet den Rückgabe-Boolean vom Stapel. Die zweite (==) vergleicht die Objektadressen direkt vom Stapel. Im ersten Fall gibt es mehr Aktivität.

Ich habe diesen Test mehrmals mit beiden IFs nacheinander durchgeführt. Das "==" ist immer etwas schneller.


Ich möchte die Antwort von polygenetischen Schmierstoffen ergänzen:

Ich persönlich bevorzuge Gleichgestellte (). Aber es gibt den Typ Kompatibilitätsprüfung. Was ich denke, ist eine wichtige Einschränkung.

Um eine Typkompatibilitätsprüfung zum Zeitpunkt der Kompilierung durchzuführen, deklarieren und verwenden Sie eine benutzerdefinierte Funktion in Ihrer Enumeration.

public boolean isEquals(enumVariable) // compare constant from left
public static boolean areEqual(enumVariable, enumVariable2) // compare two variable

Damit haben Sie alle Vorteile beider Lösungen: NPE-Schutz, einfach zu lesender Code und Typkompatibilitätsprüfung zum Zeitpunkt der Kompilierung.

Ich empfehle auch, einen UNDEFINED-Wert für enum hinzuzufügen.


Ich möchte diesen spezifischen Unterschied zwischen dem Operator == und der Methode equals() explizit hervorheben:

Die Methode equals() soll prüfen, ob der Inhalt des Objekts / der Objekte, auf die sich die Referenzvariable beziehen, gleich ist.

Der Operator == prüft, ob die beteiligten Referenzvariablen auf dasselbe Objekt verweisen.

Es ist Sache der implementierenden Klasse, diese Differenzierung je nach Bedarf der Anwendung bereitzustellen.

Andernfalls entspricht das Standardverhalten der Object (in Java), wie in http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#equals(java.lang.Object) :

Die Methode equals für die Klasse Object implementiert die höchst mögliche Äquivalenzbeziehung für Objekte. Das heißt, für alle Nicht-Null-Referenzwerte x und y gibt diese Methode true zurück true wenn und nur wenn sich x und y auf dasselbe Objekt beziehen ( x == y hat den Wert true ).


Kurz gesagt, beide haben Vor- und Nachteile.

Auf der einen Seite hat es Vorteile zu verwenden == , wie in den anderen Antworten beschrieben.

Auf der anderen Seite, wenn Sie aus irgendeinem Grund die Enums mit einem anderen Ansatz (normale Klassen Instanzen) ersetzen, verwendet == Sie beißt. (BTDT.)


Sie können verwenden: ==, equals () oder switch () blockieren für den Vergleich von Enums, alle sind technisch wahr und würden Ihrem Bedarf dienen.

In diesem Lernprogramm erfahren Sie mehr über die allgemeinen Funktionen von Enum: Verwendung von Enums in Java





enums