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
inEnum
stellt sicher, dassenum
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 einesenum
existieren, die über die durch dieenum
definierten hinausgehen.Da es nur eine Instanz jeder
enum
Konstante gibt, ist es zulässig, den Operator==
anstelle der Methodeequals
verwenden, wenn zwei Objektreferenzen verglichen werden, wenn bekannt ist, dass sich mindestens eine davon auf eineenum
Konstante bezieht . (Dieequals
Methode inEnum
ist einefinal
Methode, die nursuper.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, wenna==b
. Wenn eine Klasse diese Garantie übernimmt, können ihre Clients den Operator==
anstelle der Methodeequals(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 KlasseObject
implementiert die höchst mögliche Äquivalenzbeziehung für Objekte. Das heißt, für alle Nicht-Null-Referenzwertex
undy
gibt diese Methodetrue
zurücktrue
wenn und nur wenn sichx
undy
auf dasselbe Objekt beziehen (x == y
hat den Werttrue
).
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