1. Vergleichen von Objekten in Java
In Java können Objekte sowohl nach Referenz als auch nach Wert verglichen werden.
Referenzen vergleichen
Wenn zwei Variablen auf dasselbe Objekt im Speicher verweisen, sind die in diesen Variablen gespeicherten Referenzen gleich. Wenn Sie diese Variablen mit dem Gleichheitsoperator ( ==
) vergleichen, erhalten Sie „wahr“, und das Ergebnis ist sinnvoll. Hier ist alles einfach.
Code | Konsolenausgabe |
---|---|
|
|
Vergleich nach Wert
Es kommt jedoch häufig vor, dass sich zwei Variablen auf zwei unterschiedliche Objekte beziehen, die identisch sind. Zum Beispiel zwei verschiedene String-Objekte, die denselben Text enthalten.
Um festzustellen, ob verschiedene Objekte identisch sind, verwenden Sie die equals()
Methode. Zum Beispiel:
Code | Konsolenausgabe |
---|---|
|
|
Die equals
Methode ist nicht auf die Klasse beschränkt String
. Jede Klasse hat es.
Sogar Kurse, die Sie selbst schreiben, und hier erfahren Sie, warum.
2. Object
Klasse
Alle Klassen in Java erben die Object
Klasse. Die Entwickler von Java haben diesen Ansatz entwickelt.
Und wenn eine Klasse die Object
Klasse erbt, erhält sie alle Methoden der Object
Klasse. Und das ist eine wesentliche Folge der Vererbung.
Mit anderen Worten: Jede Klasse verfügt über die Methoden der Object
Klasse, auch wenn sie im Code nicht erwähnt werden.
Zu diesen geerbten Methoden gehören Methoden, die sich auf den Objektvergleich beziehen. Dies sind die equals()
und- hashCode()
Methoden.
Code | In Wirklichkeit werden wir Folgendes haben: |
---|---|
|
|
Im obigen Beispiel haben wir eine einfache Person
Klasse mit Namens- und Altersparametern erstellt, aber keine einzige Methode. Da jedoch alle Klassen die Object
Klasse erben, Person
verfügt die Klasse automatisch über zwei Methoden:
Methode | Beschreibung |
---|---|
|
Vergleicht das aktuelle Objekt und das übergebene Objekt |
|
Gibt den Hashcode des aktuellen Objekts zurück |
Es stellt sich heraus, dass absolut jedes Objekt über die equals
Methode verfügt und Objekte unterschiedlichen Typs miteinander verglichen werden können. Ein solcher Code wird perfekt kompiliert und funktioniert.
Code | Konsolenausgabe |
---|---|
|
|
|
|
3. equals()
Methode
Die equals()
von der Klasse geerbte Methode Object
implementiert den einfachsten Algorithmus zum Vergleich des aktuellen Objekts mit übergebenen Objekten: Sie vergleicht lediglich Verweise auf die Objekte.
Das gleiche Ergebnis erhalten Sie, wenn Sie nur Person
Variablen vergleichen, anstatt die equals()
Methode aufzurufen. Beispiel:
Code | Konsolenausgabe |
---|---|
|
|
Wenn die equals
Methode aufgerufen wird a
, vergleicht sie einfach die in der a
Variablen gespeicherte Referenz mit der in der b
Variablen gespeicherten Referenz.
Allerdings funktioniert der Vergleich für die String
Klasse anders. Warum?
Weil die Leute, die die String
Klasse erstellt haben, ihre eigene Implementierung der equals()
Methode geschrieben haben.
Implementierung der equals()
Methode
Schreiben wir nun unsere eigene Implementierung der Methode equal in der Person
Klasse. Wir betrachten 4 Hauptfälle.
equals
Methode überschreibt, verwendet sie immer ein Object
Objekt als Argument
Szenario 1 : Dasselbe Objekt, für das die Methode aufgerufen wird, wird auch an die Methode equals
übergeben . equals
Wenn die Referenzen des aktuellen Objekts und des übergebenen Objekts gleich sind, muss die Methode zurückgeben true
. Ein Objekt ist sich selbst gleich.
Im Code sieht es so aus:
Code | Beschreibung |
---|---|
|
Vergleichen Sie Referenzen |
Szenario 2 : null
wird an die Methode übergeben equals
– wir haben nichts zum Vergleich. Das Objekt, für das die equals
Methode aufgerufen wird, ist definitiv nicht null, daher müssen wir false
in diesem Fall zurückkehren.
Im Code sieht es so aus:
Code | Beschreibung |
---|---|
|
Referenzen vergleichen Ist das übergebene Objekt null ? |
Szenario 3 : Ein Verweis auf ein Objekt, das kein Objekt ist, wird an die Methode Person
übergeben . equals
Ist das Person
Objekt gleich dem Nicht- Person
Objekt? Das ist eine Frage, die der Entwickler der Person
Klasse nach Belieben entscheiden kann.
Aber normalerweise müssen Objekte derselben Klasse angehören, um als gleich zu gelten. Wenn also etwas anderes als ein Objekt der Person
Klasse an unsere Methode equal übergeben wird, geben wir immer zurück false
. Wie kann man den Typ eines Objekts überprüfen? Das ist richtig – mit dem instanceof
Operator.
So sieht unser neuer Code aus:
Code | Beschreibung |
---|---|
|
Referenzen vergleichen Ist das übergebene Objekt null ? Wenn das übergebene Objekt kein a ist Person |
4. Vergleich zweier Person
Objekte
Was haben wir am Ende herausgefunden? Wenn wir das Ende der Methode erreicht haben, haben wir eine Person
Objektreferenz, die nicht ist null
. Also konvertieren wir es in ein Person
und vergleichen die relevanten internen Daten beider Objekte. Und das ist unser viertes Szenario .
Code | Beschreibung |
---|---|
|
Referenzen vergleichen Ist das übergebene Objekt null ? Wenn das übergebene Objekt kein Person Typecasting ist |
Und wie vergleicht man zwei Person
Objekte? Sie sind gleich, wenn sie den gleichen Namen ( name
) und das gleiche Alter ( age
) haben. Der endgültige Code sieht folgendermaßen aus:
Code | Beschreibung |
---|---|
|
Referenzen vergleichen Ist das übergebene Objekt null ? Wenn das übergebene Objekt kein Person Typecasting ist |
Aber das ist nicht alles.
Erstens ist das Namensfeld ein String
, daher müssen Sie das Namensfeld vergleichen, indem Sie die equals
Methode aufrufen.
this.name.equals(person.name)
Zweitens name
kann das Feld sein null
: In diesem Fall können Sie equals
es nicht aufrufen. Sie benötigen eine zusätzliche Prüfung für null
:
this.name != null && this.name.equals(person.name)
Wenn sich das Namensfeld jedoch null
in beiden Person
Objekten befindet, sind die Namen immer noch gleich.
Der Code für das vierte Szenario könnte so aussehen:
|
Wenn das Alter nicht gleich ist, macht ein return false Vergleich mit der Methode keinen Sinn . Hier ist entweder das zweite Feld gleich oder nicht. Vergleichen Sie die beiden Namensfelder mit der Methode. this.name null equals name null equals |
5. hashCode()
Methode
Neben der equals
Methode, die einen detaillierten Vergleich aller Felder beider Objekte durchführen soll, gibt es eine weitere Methode, die für einen ungenauen, aber sehr schnellen Vergleich verwendet werden kann: hashCode()
.
Stellen Sie sich vor, Sie sortieren eine Liste mit Tausenden von Wörtern alphabetisch und müssen wiederholt Wortpaare vergleichen. Und die Wörter sind lang und bestehen aus vielen Buchstaben. Generell würde ein solcher Vergleich sehr lange dauern.
Aber es kann beschleunigt werden. Angenommen, wir haben Wörter, die mit unterschiedlichen Buchstaben beginnen – es ist sofort klar, dass sie unterschiedlich sind. Aber wenn sie mit denselben Buchstaben beginnen, können wir noch nicht sagen, wie das Ergebnis aussehen wird: Es kann sein, dass die Wörter gleich oder unterschiedlich sind.
Die hashCode()
Methode funktioniert nach einem ähnlichen Prinzip. Wenn Sie es für ein Objekt aufrufen, gibt es eine Zahl zurück – analog zum ersten Buchstaben eines Wortes. Diese Nummer hat die folgenden Eigenschaften:
- Identische Objekte haben immer den gleichen Hashcode
- Verschiedene Objekte können denselben Hashcode haben oder ihre Hashcodes können unterschiedlich sein
- Wenn Objekte unterschiedliche Hashcodes haben, dann sind die Objekte definitiv unterschiedlich
Um dies noch deutlicher zu machen, formulieren wir diese Eigenschaften in Worte:
- Identische Wörter haben immer die gleichen Anfangsbuchstaben.
- Verschiedene Wörter können die gleichen Anfangsbuchstaben haben oder ihre Anfangsbuchstaben können unterschiedlich sein
- Wenn Wörter unterschiedliche Anfangsbuchstaben haben, dann sind die Wörter definitiv unterschiedlich
Die letzte Eigenschaft wird verwendet, um den Vergleich von Objekten zu beschleunigen:
Zunächst werden die Hashcodes der beiden Objekte berechnet. Wenn diese Hashcodes unterschiedlich sind, dann sind die Objekte definitiv unterschiedlich und es besteht keine Notwendigkeit, sie weiter zu vergleichen.
Wenn die Hashcodes jedoch gleich sind, müssen wir die Objekte immer noch mit der Methode „equals“ vergleichen.
6. Verträge im Code
Das oben beschriebene Verhalten muss von allen Klassen in Java implementiert werden. Beim Kompilieren gibt es keine Möglichkeit zu überprüfen, ob Objekte korrekt verglichen werden.
Java-Programmierer sind sich allgemein darüber einig, dass sie, wenn sie ihre eigene Implementierung der Methode equal() schreiben und dadurch die Standardimplementierung (in der Object
Klasse) überschreiben, auch ihre eigene Implementierung der hashCode()
Methode so schreiben müssen, dass die oben genannten Regeln gelten befriedigt.
Diese Vereinbarung wird als Vertrag bezeichnet .
Wenn Sie nur die equals()
oder nur die hashCode()
Methode in Ihrer Klasse implementieren, verstoßen Sie grob gegen den Vertrag (Sie haben die Vereinbarung gebrochen). Tun Sie das nicht.
Wenn andere Programmierer Ihren Code verwenden, funktioniert er möglicherweise nicht richtig. Darüber hinaus verwenden Sie Code, der auf der Einhaltung der oben genannten Verträge basiert.
Bei der Suche nach einem Element vergleichen alle Java-Sammlungen zunächst die Hashcodes von Objekten und führen erst dann einen Vergleich mit der equals
Methode durch.
Das heißt, wenn Sie Ihrer eigenen Klasse eine equals
Methode geben, aber keine eigene hashCode()
Methode schreiben oder diese falsch implementieren, funktionieren Sammlungen möglicherweise nicht richtig mit Ihren Objekten.
Sie könnten beispielsweise ein Objekt zu einer Liste hinzufügen und dann mit der contains()
Methode danach suchen, aber die Sammlung findet Ihr Objekt möglicherweise nicht.