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 equalsMethode ist nicht auf die Klasse beschränkt String. Jede Klasse hat es.
Sogar Kurse, die Sie selbst schreiben, und hier erfahren Sie, warum.
2. ObjectKlasse
Alle Klassen in Java erben die ObjectKlasse. Die Entwickler von Java haben diesen Ansatz entwickelt.
Und wenn eine Klasse die ObjectKlasse erbt, erhält sie alle Methoden der ObjectKlasse. Und das ist eine wesentliche Folge der Vererbung.
Mit anderen Worten: Jede Klasse verfügt über die Methoden der ObjectKlasse, 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 PersonKlasse mit Namens- und Altersparametern erstellt, aber keine einzige Methode. Da jedoch alle Klassen die ObjectKlasse erben, Personverfü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 equalsMethode 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 Objectimplementiert 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 PersonVariablen vergleichen, anstatt die equals()Methode aufzurufen. Beispiel:
| Code | Konsolenausgabe |
|---|---|
|
|
Wenn die equalsMethode aufgerufen wird a, vergleicht sie einfach die in der aVariablen gespeicherte Referenz mit der in der bVariablen gespeicherten Referenz.
Allerdings funktioniert der Vergleich für die StringKlasse anders. Warum?
Weil die Leute, die die StringKlasse 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 PersonKlasse. Wir betrachten 4 Hauptfälle.
equalsMethode überschreibt, verwendet sie immer ein
ObjectObjekt als Argument
Szenario 1 : Dasselbe Objekt, für das die Methode aufgerufen wird, wird auch an die Methode equalsübergeben . equalsWenn 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 : nullwird an die Methode übergeben equals– wir haben nichts zum Vergleich. Das Objekt, für das die equalsMethode aufgerufen wird, ist definitiv nicht null, daher müssen wir falsein 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 . equalsIst das PersonObjekt gleich dem Nicht- PersonObjekt? Das ist eine Frage, die der Entwickler der PersonKlasse 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 PersonKlasse 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 instanceofOperator.
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 PersonObjekte
Was haben wir am Ende herausgefunden? Wenn wir das Ende der Methode erreicht haben, haben wir eine PersonObjektreferenz, die nicht ist null. Also konvertieren wir es in ein Personund 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 PersonObjekte? 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 equalsMethode aufrufen.
this.name.equals(person.name)
Zweitens namekann das Feld sein null: In diesem Fall können Sie equalses 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 nullin beiden PersonObjekten 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.namenullequalsnamenullequals |
5. hashCode()Methode
Neben der equalsMethode, 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 ObjectKlasse) ü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 equalsMethode durch.
Das heißt, wenn Sie Ihrer eigenen Klasse eine equalsMethode 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.
GO TO FULL VERSION