Når du override equals() for at definere logisk lighed, skal du også override hashCode() — fordi hash-baserede samlinger (HashMap, ) er afhængige af kontrakten om at . At bryde dette fører til subtile, svært at finde fejl.
HashSet// by default, equals() compares IDENTITY (same object?), hashCode() is based on memory address
Person p1 = new Person("Ann", 30);
Person p2 = new Person("Ann", 30);
p1.equals(p2); // false by default — different objects, even with same data
Uden override er to objekter med identisk indhold "ikke lige" — normalt ikke det du ønsker for værdibjekter.
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person p = (Person) o;
return age == p.age && Objects.equals(name, p.name); // compare by CONTENT
}
@Override
public int hashCode() {
return Objects.hash(name, age); // MUST be consistent with equals()
}
Kontrakten: hvis a.equals(b) er true, så SKAL a.hashCode() == b.hashCode() være true.
Person p1 = new Person("Ann", 30);
Person p2 = new Person("Ann", 30); // equal by our equals()
Set<Person> set = new HashSet<>();
set.add(p1);
set.contains(p2); // ❌ likely FALSE — even though p1.equals(p2)!
Hvorfor? HashMap/HashSet bruger først hashCode() til at finde den rigtige bucket, og derefter equals() inden i den. Med standard (identitetsbaseret) hashCode(), p1 og p2 ender i forskellige buckets, så contains sammenligner dem aldrig — sættet tror de er forskellige. Dette producerer forvirrende fejl: duplikater i et Set, mislykkede map-opslag, osv.
1. equal objects → equal hash codes (REQUIRED for correctness)
2. unequal objects MAY have the same hash (collisions are allowed)
3. hashCode() must be consistent (same object → same code, unchanged)
4. equals() must be reflexive, symmetric, transitive, consistent
record Person(String name, int age) {} // records auto-generate equals/hashCode/toString!
Java records (og IDE-generation / Lombok) producerer korrekt, konsistent equals/hashCode for dig.
equals/hashCode-kontrakten er en af Javas vigtigste — og hyppigst overtrådt — regler.
At override equals() uden hashCode() bryder hash-baserede samlinger på måder der er svært at debugge: objekter du anser for lige "bliver væk" i HashMap/HashSet (mislykkede opslag, phantom-duplikater) fordi de hasher til forskellige buckets.
Da disse samlinger er allestedsnærværende, skal hver værdi-typeklasse brugt som nøgle eller set-element override begge dele konsistent.
At forstå hvorfor (bucket-derefter-lighed-opslag-mekanismen) — og at bruge records eller genereret kode for at få det rigtigt — er essentielt for korrekt adfærd og et klassisk interviewemne der afslører rigtig forståelse af hvordan Java-samlinger fungerer.