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 dieselbe Speicherstelle verweisen. Um den tatsächlichen Inhalt von Objekten zu vergleichen, musst du die Methode equals() ü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 Methode equals() folgt einem Standardmuster: Prüfe zuerst, ob es dasselbe Objekt ist, verifiziere dann den Typ und vergleiche schließlich die relevanten Felder.
Wenn du equals() überschreibst, musst du auch hashCode() überschreiben. Das ist eine Vertragspflicht in Java: Gleiche Objekte müssen denselben Hashcode haben. Hashbasierte Sammlungen wie HashMap und HashSet sind auf diese Regel angewiesen, um korrekt zu funktionieren.
@Override
public int hashCode() {
return Objects.hash(name, age);
}Die Hilfsmethode Objects.hash() erzeugt einen Hashcode aus denselben Feldern, die auch in equals() verwendet werden. Wenn zwei Person-Objekte denselben Namen und dasselbe Alter haben, gelten sie als gleich und erzeugen identische Hashcodes, wodurch ein konsistentes Verhalten in Collections gewährleistet wird.
Aufgabe
EinfachErstellen wir ein Studentenverwaltungssystem, das die Objektgleichheit korrekt implementiert. Du erstellst eine Klasse Student, in der zwei Studierende als gleich gelten, wenn sie dieselbe Matrikelnummer und denselben Namen haben, unabhängig davon, ob sie dasselbe Objekt im Speicher sind.
Du organisierst deinen Code auf zwei Dateien:
Student.java: Erstelle eine Klasse, die einen Studierenden mit drei privaten Feldern darstellt:studentId(String),name(String) undgpa(double). Füge einen Konstruktor hinzu, der alle Felder initialisiert, sowie Getter-Methoden für jedes Feld.Überschreibe die Methode
equals(), sodass zwei Student-Objekte als gleich gelten, wenn sie dieselbestudentIdUND denselbennamehaben. Halte dich an das Standardmuster: Prüfe, ob es sich um dieselbe Referenz handelt, prüfe auf null und den Typ und vergleiche dann die relevanten Felder.Überschreibe die Methode
hashCode()mitObjects.hash()und verwende dabei dieselben Felder wie inequals(). Denke daran,java.util.Objectsam Anfang deiner Datei zu importieren.Main.java: Erwecke deine Student-Klasse zum Leben, indem du Student-Objekte vergleichst. Du erhältst sechs Eingaben, die zwei Studierende darstellen: zuerst die ID, den Namen und den Notendurchschnitt des ersten Studierenden, gefolgt von der ID, dem Namen und dem Notendurchschnitt des zweiten Studierenden.Erstelle beide Student-Objekte, führe dann drei Vergleiche durch und gib die Ergebnisse aus:
- Gib
Same reference:aus, gefolgt davon, ob der erste Studierende mit sich selbst gleich ist (sollte immer true sein) - Gib
Content equality:aus, gefolgt davon, ob der erste Studierende mit dem zweiten Studierenden gleich ist (basierend auf deiner equals-Implementierung) - Gib
Hash codes match:aus, gefolgt davon, ob beide Studierenden denselben Hash-Code haben
- Gib
Du erhältst sechs Eingaben: die ID des ersten Studierenden (String), den Namen des ersten Studierenden (String), den Notendurchschnitt des ersten Studierenden (double), die ID des zweiten Studierenden (String), den Namen des zweiten Studierenden (String) und den Notendurchschnitt des zweiten Studierenden (double).
Beachte: Wenn zwei Studierende übereinstimmende IDs und Namen haben, gibt equals() true zurück UND ihre Hash-Codes stimmen überein. Diesen Vertrag musst du einhalten!
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 einlesen
String id1 = scanner.nextLine();
String name1 = scanner.nextLine();
double gpa1 = scanner.nextDouble();
scanner.nextLine(); // Zeilenumbruch einlesen
// Daten des zweiten Studenten einlesen
String id2 = scanner.nextLine();
String name2 = scanner.nextLine();
double gpa2 = scanner.nextDouble();
// TODO: Zwei Student-Objekte aus den Eingabedaten erstellen
// TODO: "Same reference: " ausgeben, gefolgt von der Angabe, ob student1 gleich sich selbst ist
// TODO: "Content equality: " ausgeben, gefolgt von der Angabe, ob student1 gleich student2 ist
// TODO: "Hash codes match: " ausgeben, gefolgt von der Angabe, ob beide Studenten denselben Hashcode 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 Schlüsselwort thisMethodenFelder (Attribute)KonstruktormethodeÜberladen von KonstruktorenRückblick – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbung (extends)Das Schlüsselwort superÜberschreiben von Methoden (@Override)KonstruktorverkettungDie Object-KlasseEinfach- und mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenRückblick – Mitarbeiterhierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-SchnittstelleRückblick – Benutzerdefinierte Sortierung2Zugriffsmodifikatoren & Kapselung
Übersicht der ZugriffsebenenGetter- und Setter-MethodenInformationsverbergungDas Schlüsselwort finalRückblick – Bankkontoverwaltung5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenRückblick – Formrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, verschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Versiegelte Klassen (Java 17+)11Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterBuilder-MusterObserver-MusterStrategie-Muster14Abschließende Herausforderungen
E-Learning-PlattformBankingsystemEntwicklung einer SpielfigurFahrzeugvermietungsdienst3Klassen-Props & statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Wiederholung – Counter & Utility6Schnittstellen & abstrakte Klassen
Einführung in InterfacesInterfaces implementierenMehrere Interfaces implementierenDefault & Static in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesRückblick – ZahlungssystemÜbe selbstständig: Online-Java-Compiler