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 zeigen. Um den tatsächlichen Inhalt von Objekten zu vergleichen, musst du 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 Methode equals() folgt einem Standardmuster: Prüfe zunächst, ob es dasselbe Objekt ist, überprüfe dann den Typ und vergleiche schließlich die relevanten Felder.
Wenn du equals() überschreibst, musst du 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() erzeugt einen Hash-Code aus denselben Feldern, die in equals() verwendet werden. Wenn zwei Person-Objekte denselben Namen und dasselbe Alter haben, werden sie als gleich betrachtet und erzeugen identische Hash-Codes, wodurch ein konsistentes Verhalten in Sammlungen sichergestellt wird.
Aufgabe
EinfachErstellen wir ein Studentenverwaltungssystem, das die Objektgleichheit korrekt implementiert. Du erstellst eine Student-Klasse, bei der zwei Studenten als gleich gelten, wenn sie dieselbe Studenten-ID und denselben Namen haben, unabhängig davon, ob sie dasselbe Objekt im Speicher sind.
Du organisierst deinen Code auf zwei Dateien verteilt:
Student.java: Erstelle eine Klasse, die einen Studenten mit drei privaten Feldern repräsentiert: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. Befolge das Standardmuster: Prüfe, ob es sich um dieselbe Referenz handelt, prüfe auf null und den Typ und vergleiche anschließend die relevanten Felder.Überschreibe die Methode
hashCode()mithilfe vonObjects.hash()und verwende dabei dieselben Felder wie inequals(). Denke daran, oben in deiner Dateijava.util.Objectszu importieren.Main.java: Erwecke deine Student-Klasse zum Leben, indem du Studentenobjekte vergleichst. Du erhältst 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.Erstelle beide Student-Objekte und führe anschließend drei Vergleiche durch, deren Ergebnisse du ausgibst:
- Gib
Same reference:aus, gefolgt davon, ob der erste Student gleich sich selbst ist (sollte immer true sein) - Gib
Content equality:aus, gefolgt davon, ob der erste Student gleich dem zweiten Studenten ist (basierend auf deiner Implementierung von equals) - Gib
Hash codes match:aus, gefolgt davon, ob beide Studenten denselben Hash-Code haben
- Gib
Du erhältst sechs Eingaben: die ID des ersten Studenten (String), den Namen des ersten Studenten (String), den GPA des ersten Studenten (double), die ID des zweiten Studenten (String), den Namen des zweiten Studenten (String) und den GPA des zweiten Studenten (double).
Beachte, dass bei zwei Studenten mit übereinstimmenden IDs und Namen sowohl equals() true zurückgibt ALS AUCH ihre Hash-Codes übereinstimmen. Dies ist der Vertrag, den du einhalten musst!
Probier es selbst
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Lese die Daten des ersten Studenten
String id1 = scanner.nextLine();
String name1 = scanner.nextLine();
double gpa1 = scanner.nextDouble();
scanner.nextLine(); // Zeilenumbruch verbrauchen
// Lese die Daten des zweiten Studenten
String id2 = scanner.nextLine();
String name2 = scanner.nextLine();
double gpa2 = scanner.nextDouble();
// TODO: Erstelle zwei Student-Objekte mit den Eingabedaten
// TODO: Print "Same reference: " followed by whether student1 equals itself
// TODO: Print "Content equality: " followed by whether student1 equals student2
// TODO: Print "Hash codes match: " followed by whether both students have the same hash code
}
}
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