Vor einigen Monaten hatte ich eine kurze Diskussion in einem Merge Request mit einem erfahrenem Entwickler, der mich
darum
gebeten hat, mein Refactoring Rückgänig zu machen weil ==
leichter zu lesen sei.
Was war passiert?
Ich hatte ganz in der “Clean Code Manier” Code besser hinterlassen, als ich ihn vorgefunden hatte. Ich bin über eine
Stelle im Code
gestolper, bei der Objekte, genauer gesagt Boolean
mit ==
verglichen wurden. Das habe ich natürlich korrigiert zu
einem Vergleich mit
equlas()
. Daraufhin bekam ich die Bitte dies wieder auf ==
umzustellen, das es leichter zu lesen sei.
Das habe ich natürlich abgelehnt und folgende Erklärung geliefert.
Warum .equals()
und nicht ==
für Objektvergleiche in Java?
Hallo zusammen,
heute geht es um einen wichtigen Unterschied in Java, der oft zu Fehlern führt: den Vergleich von Objekten. Während der
==
-Operator bei primitiven Datentypen wie int
oder boolean
problemlos funktioniert, sollten wir bei Objekten immer
die .equals()
-Methode verwenden. Aber warum ist das so? Und was passiert, wenn wir es nicht tun?
==
vs. .equals()
– Ein grundlegender Unterschied
Der ==
-Operator vergleicht in Java Referenzen. Das bedeutet, er prüft, ob zwei Variablen auf dasselbe Objekt im
Speicher zeigen. Bei primitiven Datentypen ist das kein Problem, da diese direkt ihren Wert speichern. Bei Objekten
hingegen speichern Variablen nur Verweise (Referenzen) auf die eigentlichen Objekte.
Die .equals()
-Methode hingegen vergleicht standardmäßig auch Referenzen (wie in der Object
Klasse definiert). Viele
Klassen, wie z.B. String
, Integer
oder eben auch Boolean
, überschreiben diese Methode jedoch, um einen *
inhaltlichen Vergleich* durchzuführen. Sie prüft also, ob zwei Objekte den gleichen Wert haben, auch wenn sie
unterschiedliche Speicheradressen belegen.
Das Problem demonstriert am Beispiel von Boolean
Betrachten wir folgendes Beispiel mit Boolean
-Objekten:
Boolean a = new Boolean(true);
Boolean b = new Boolean(true);
Boolean c = a;
System.out.println(a == b); // Ausgabe: false
System.out.println(a.equals(b)); // Ausgabe: true
System.out.println(a == c); // Ausgabe: true
Was passiert hier?
a == b
:a
undb
sind zwei unterschiedlicheBoolean
-Objekte, auch wenn sie den gleichen Wert (true
) haben.==
vergleicht die Referenzen und findet, dass sie unterschiedlich sind.a.equals(b)
: Dieequals()
-Methode derBoolean
-Klasse vergleicht die Werte der Objekte. Da beidetrue
sind, gibt.equals()
true
zurück.a == c
:c
wurde auf die gleiche Referenz wiea
gesetzt. Daher zeigen beide Variablen auf dasselbe Objekt im Speicher, und==
gibttrue
zurück.
Warum .equals()
die bessere Wahl ist
In den meisten Fällen wollen wir wissen, ob zwei Objekte den gleichen inhaltlichen Wert haben, nicht ob sie zufällig
an derselben Speicheradresse liegen. Die .equals()
-Methode gibt uns diese Möglichkeit.
Best Practice: Verwendet für den Vergleich von Objekten immer die .equals()
-Methode (sofern sie sinnvoll
überschrieben wurde). Der ==
-Operator sollte Objekten nur in sehr speziellen Fällen verwendet werden, z.B. wenn man
explizit prüfen möchte, ob zwei Variablen auf dasselbe Objekt zeigen (z.B. in bestimmten Performance-kritischen
Situationen oder bei der Implementierung von equals()
selbst).
Wann muss ich equals()
überschreiben?
Wenn ihr eigene Klassen erstellt, erbt diese die Standardimplementierung von equals()
von der Object
Klasse. Diese
Standardimplementierung vergleicht nur Referenzen. Wenn ihr also wollt, dass Objekte eurer Klasse anhand ihrer Attribute
verglichen werden können, müsst ihr die equals()
-Methode überschreiben.
Denkt daran, dass ihr beim Überschreiben von equals()
auch die hashCode()
-Methode überschreiben solltet, um die
Konsistenz mit Hash-basierten Datenstrukturen (wie HashMap
oder HashSet
) zu gewährleisten.
Fazit
Der Vergleich von Objekten in Java kann tückisch sein. Mit diesem Wissen seid ihr aber bestens gerüstet, um die Fallstricke zu vermeiden und korrekten, robusten Code zu schreiben.
Habt ihr noch Fragen oder Anmerkungen? Lasst es mich wissen!