Ko overridaš equals() za definiranje logične enakosti, moraš tudi overridati hashCode() — ker se zbirke na osnovi heša (HashMap, ) zanašajo na pogodbo, da . Prekršitev tega vodi do subtilnih, težko najdljivih napak.
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
Brez overridanja sta dva objekta z enako vsebino "neenaka" — navadno ne želiš tega za objekte vrednosti.
@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()
}
Pogodba: če je a.equals(b) true, potem mora biti a.hashCode() == b.hashCode() 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)!
Zakaj? HashMap/HashSet najprej uporabita hashCode() za iskanje prave prihrambne celice, nato equals() znotraj nje. Z privzetim (identitetniškim) hashCode() se p1 in p2 znajdeta v različnih prihrambnah celicah, zato contains ju nikoli ne primerja — nabor misli, da sta drugačna. To povzroči zmešnjave napake: podvojke v Set, neuspešne iskalne naslove itd.
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 (in ustvarjanje IDE-ja / Lombok) ti ustvarijo pravilna, skladna equals/hashCode samodejno.
Pogodba equals/hashCode je eno najpomembnejših — in najčešće kršenih — pravil v Javi.
Overidanje equals() brez hashCode() prekrši zbirke na osnovi heša na načine, ki se jih težko debugira: objekti, ki jih smatraš za enake, se "zgubijo" v HashMap/HashSet (neuspešni iskalni naslovi, fantomski podvojki), ker se hešajo v različne prihambne celice.
Ker so te zbirke vseprisotne, mora vsak razred vrsti vrednosti, ki se uporablja kot ključ ali element nabora, overridati oba dosledno.
Razumevanje zakaj (mehanizem iskanja po prihrambi-nato-enakosti) — in uporaba recordov ali ustvarjene kode za pravilnost — je bistveno za pravilno vedenje in klasična tema intervjuja, ki razodene pravo razumevanje, kako delujejo zbirke v Javi.