equals() und hashCode()
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 42 von 87.
Beim Vergleichen von Objekten in Java prüft der ==-Operator, ob zwei Referenzen auf denselben Speicherort zeigen. Um den tatsächlichen Inhalt von Objekten zu vergleichen, müssen Sie die equals()-Methode überschreiben.
public class Person {
private String name;
private int age;
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && name.equals(person.name);
}
}Die equals()-Methode folgt einem Standardmuster: Zuerst wird geprüft, ob es sich um dasselbe Objekt handelt, dann wird der Typ überprüft und schließlich werden die relevanten Felder verglichen.
Wann immer Sie equals() überschreiben, müssen Sie auch hashCode() überschreiben. Dies ist ein Vertrag in Java: Objekte, die gleich sind, müssen denselben Hash-Code haben. Hash-basierte Sammlungen wie HashMap und HashSet verlassen sich auf diese Regel, um korrekt zu funktionieren.
@Override
public int hashCode() {
return Objects.hash(name, age);
}Die Hilfsmethode Objects.hash() generiert einen Hash-Code aus denselben Feldern, die in equals() verwendet werden. Wenn zwei Person-Objekte denselben name und dasselbe age haben, werden sie als gleich betrachtet und erzeugen identische Hash-Codes, was ein konsistentes Verhalten in Collections gewährleistet.
Aufgabe
EinfachLassen Sie uns ein Studenten-Erfassungssystem erstellen, das die Objektgleichheit korrekt implementiert. Sie werden eine Student-Klasse erstellen, in der zwei Studenten als gleich gelten, wenn sie dieselbe Studenten-ID und denselben Namen haben – unabhängig davon, ob es sich um dasselbe Objekt im Speicher handelt.
Sie werden Ihren Code in zwei Dateien organisieren:
Student.java: Erstellen Sie eine Klasse, die einen Studenten mit drei privaten Feldern repräsentiert:studentId(String),name(String) undgpa(double). Fügen Sie einen Konstruktor zur Initialisierung aller Felder und Getter-Methoden für jedes Feld hinzu.Überschreiben Sie die
equals()-Methode so, dass zwei Student-Objekte als gleich betrachtet werden, wenn sie dieselbestudentIdUND denselbennamehaben. Folgen Sie dem Standardmuster: Prüfen Sie auf dieselbe Referenz, prüfen Sie auf null und den Typ, und vergleichen Sie dann die relevanten Felder.Überschreiben Sie die
hashCode()-Methode unter Verwendung vonObjects.hash()mit denselben Feldern, die inequals()verwendet werden. Denken Sie daran,java.util.Objectsam Anfang Ihrer Datei zu importieren.Main.java: Erwecken Sie Ihre Student-Klasse zum Leben, indem Sie Studenten-Objekte vergleichen. Sie erhalten sechs Eingaben, die zwei Studenten repräsentieren: die ID, den Namen und den GPA des ersten Studenten, gefolgt von der ID, dem Namen und dem GPA des zweiten Studenten.Erstellen Sie beide Student-Objekte, führen Sie dann drei Vergleiche durch und geben Sie die Ergebnisse aus:
- Geben Sie
"Same reference: "aus, gefolgt davon, ob der erste Student sich selbst gleicht (sollte immer true sein) - Geben Sie
"Content equality: "aus, gefolgt davon, ob der erste Student dem zweiten Studenten gleicht (basierend auf Ihrer equals-Implementierung) - Geben Sie
"Hash codes match: "aus, gefolgt davon, ob beide Studenten denselben Hash-Code haben
- Geben Sie
Sie erhalten sechs Eingaben: ID des ersten Studenten (String), Name des ersten Studenten (String), GPA des ersten Studenten (double), ID des zweiten Studenten (String), Name des zweiten Studenten (String) und GPA des zweiten Studenten (double).
Beachten Sie, dass wenn zwei Studenten übereinstimmende IDs und Namen haben, sowohl equals() true zurückgibt ALS AUCH ihre Hash-Codes übereinstimmen – dies ist der Vertrag, den Sie einhalten müssen!
Spickzettel
Der ==-Operator prüft, ob zwei Referenzen auf denselben Speicherort zeigen, nicht ob Objekte denselben Inhalt haben.
Um den Objektinhalt zu vergleichen, überschreiben Sie die equals()-Methode nach diesem Muster:
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // Dieselbe Referenz
if (obj == null || getClass() != obj.getClass()) return false; // Null oder anderer Typ
Person person = (Person) obj; // In den richtigen Typ umwandeln
return age == person.age && name.equals(person.name); // Felder vergleichen
}Wann immer Sie equals() überschreiben, müssen Sie auch hashCode() überschreiben. Dies ist ein Java-Vertrag: Gleiche Objekte müssen denselben Hash-Code haben.
@Override
public int hashCode() {
return Objects.hash(name, age);
}Verwenden Sie Objects.hash() mit denselben Feldern, die in equals() verwendet werden. Dies stellt sicher, dass Hash-basierte Sammlungen wie HashMap und HashSet korrekt funktionieren.
Probier es selbst
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Daten des ersten Studenten lesen
String id1 = scanner.nextLine();
String name1 = scanner.nextLine();
double gpa1 = scanner.nextDouble();
scanner.nextLine(); // Zeilenumbruch konsumieren
// Daten des zweiten Studenten lesen
String id2 = scanner.nextLine();
String name2 = scanner.nextLine();
double gpa2 = scanner.nextDouble();
// TODO: Zwei Student-Objekte mit den Eingabedaten erstellen
// TODO: "Same reference: " ausgeben, gefolgt davon, ob student1 sich selbst gleicht
// TODO: "Content equality: " ausgeben, gefolgt davon, ob student1 student2 gleicht
// TODO: "Hash codes match: " ausgeben, gefolgt davon, ob beide Studenten denselben Hash-Code haben
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenFelder (Attribute)Konstruktor-MethodeKonstruktor-ÜberladungRückblick – Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (extends)Das super-SchlüsselwortMethoden überschreiben (@Override)Konstruktor-VerkettungDie Object-KlasseEinfache & mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-InterfaceZusammenfassung – Benutzerdefiniertes Sortieren2Zugriffsmodifikatoren & Kapselung
Überblick über ZugriffsebenenGetter- und Setter-MethodenInformation HidingDas final-SchlüsselwortRückblick – Bankkonto-Manager5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenZusammenfassung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, geschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Sealed Classes (Java 17+)11Design Patterns Teil 1
Einführung in Design PatternsSingleton-PatternFactory-PatternBuilder-PatternObserver-PatternStrategy-Pattern14Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung3Klasseneigenschaften & Statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Zusammenfassung – Zähler & Utility6Interfaces & Abstrakte Klassen
Einführung in InterfacesInterfaces implementierenImplementierung mehrerer InterfacesDefault- & statische Methoden in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesZusammenfassung - Zahlungssystem