Når du overstyrer equals() for å definere logisk likhet, må du også overstyre hashCode() — fordi hash-baserte samlinger (HashMap, ) avhenger av kontrakten at . Brudd på dette fører til subtile, vanskelig å finne bugs.
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
Uten overstyrring er to objekter med identisk innhold "ikke like" — vanligvis ikke det du ønsker for verdi-objekter.
@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 sann, må a.hashCode() == b.hashCode() være sann.
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 bruker først hashCode() for å finne riktig bøtte, deretter equals() innenfor den. Med standardoppførselen (identitets-basert) hashCode(), lander p1 og p2 i ulike bøtter, så contains sammenligner dem aldri — settet tror de er ulike. Dette produserer forvirrende bugs: duplikater i et Set, mislykkede map-oppslag, 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-generering / Lombok) produserer riktig, konsistent equals/hashCode for deg.
Kontrakten for equals/hashCode er en av Javas viktigste — og hyppigst brutt — regler.
Att overstyre equals() uten hashCode() bryter hash-baserte samlinger på måter som er vanskelig å feilsøke: objekter du anser som like blir "tapt" i HashMap/HashSet (mislykkede oppslag, fantom-duplikater) fordi de hasher til ulike bøtter.
Siden disse samlingene er allestedsnærværende, må hver verdi-type klasse som brukes som nøkkel eller set-element overstyre begge konsistent.
Å forstå hvorfor (mekanismen for bøtte-så-equals oppslag) — og bruke records eller generert kode for å få det riktig — er essensielt for riktig oppførsel og et klassisk intervju-tema som avslører reell forståelse av hvordan Javas samlinger fungerer.