Kur zëvendësoni equals() për të përcaktuar barazinë logjike, duhet të zëvendësoni gjithashtu hashCode() — sepse koleksionet e bazuara në hash (, ) mbështeten në kontratën që . Shkelja e kësaj çon në gabime delikate, të vështira për t'u gjetur.
Kur zëvendësoni equals() për të përcaktuar barazinë logjike, duhet të zëvendësoni gjithashtu hashCode() — sepse koleksionet e bazuara në hash (, ) mbështeten në kontratën që . Shkelja e kësaj çon në gabime delikate, të vështira për t'u gjetur.
HashMapHashSet// 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
Pa zëvendësuar, dy objektet me përmbajtje identike nuk janë "të barabartë" — zakonisht jo ajo që dëshironi për objektet e vlerës.
@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()
}
Kontrata: nëse a.equals(b) është e vërtetë, atëherë a.hashCode() == b.hashCode() DUHET të jetë e vërtetë.
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)!
Pse? HashMap/HashSet fillimisht përdorin hashCode() për të gjetur bucket të duhur, më pas equals() brenda tij. Me hashCode() të paracaktuar (të bazuar në identitet), p1 dhe p2 bien në bucket të ndryshme, kështu që contains nuk i krahason kurrë — grupi mendon se janë të ndryshme. Kjo prodhon gabime zbavitëse: duplikatë në një Set, kërkime të dështesuara në hartë, etj.
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 (dhe gjenerimi IDE / Lombok) prodhojnë equals/hashCode të saktë dhe të qëndrueshëm për ju.
Kontrata equals/hashCode është një nga rregullat më të rëndësishme të Java-s — dhe më shpesh të shkelur.
Zëvendësimi i equals() pa hashCode() prish koleksionet e bazuara në hash në mënyra të vështira për të debuguar: objektet që konsideroni të barabartë "humbasin" në HashMap/HashSet (kërkime të dështesuara, duplikatë fantazme) sepse kanë hash në bucket të ndryshme.
Meqenëse këto koleksione janë të përhapur, çdo klasë e tipit vlerë e përdorur si çelës ose element grupi duhet të zëvendësojë të dyja në mënyrë të qëndrueshme.
Kuptohet përse (mekanizmi i kërkimit bucket-pastaj-equals) — dhe përdorimi i records ose kodit të gjeneruar për ta marrë saktë — është thelbësor për sjellje të saktë dhe është një temë klasike për intervista që zbulon kuptimin e vërtetë se si funksionojnë koleksionet Java.
Një bibliotekë pyetjesh intervistash IT me përgjigje të detajuara — nga Junior te Senior.
Dhuro