Middle
Prečo je dôležité prepísať metódy equals a hashCode v Jave?
sobes.tech AI
Odpoveď od AI
Predefinovanie equals a hashCode je dôležité pre správnu prácu s objektmi v kolekciách a pri porovnávaní.
- Symetria: Ak
a.equals(b)vraciatrue, potomb.equals(a)by tiež malo byťtrue. - Reflexivita: Pre akýkoľvek nenulový objekt
a,a.equals(a)by malo byťtrue. - Transitivita: Ak
a.equals(b)ab.equals(c)vracajútrue, potom by malo byťa.equals(c)tiežtrue. - Konzistencia: Opakované volania
a.equals(b)by mali konzistentne vracaťtruealebofalse, ak sa nezmenia informácie použité v porovnaníequals.
Pre hashCode:
- Konzistencia: Ak informácie používané v
equalsnie sú zmenené, opakované volaniahashCodena tom istom objekte by mali vracať rovnakú celočíselnú hodnotu. - Väzba s
equals: Ak sú dva objekty rovnaké podľaequals, potom ichhashCodeby mal byť rovnaký. - Optimalizácia: Nie je potrebné, aby ak sú dva objekty nerovnaké podľa
equals, ichhashCodevýsledky boli odlišné, ale generovanie odlišných hash kódov pre odlišné objekty môže zlepšiť výkon hash tabuliek.
Porušenie týchto pravidiel vedie k nepredvídateľnému správaniu pri používaní kolekcií ako HashSet, HashMap, ArrayList a ďalších, ktoré sa spoliehajú na správnu implementáciu týchto metód pre správne určenie rovnosti objektov a ich umiestnenie.
Napríklad:
// Príklad triedy bez správnych `equals` a `hashCode`
class PersonBroken {
private String name;
private int age;
public PersonBroken(String name, int age) {
this.name = name;
this.age = age;
}
// getteri vynechané pre stručnosť
}
// Príklad triedy so správnymi `equals` a `hashCode`
class PersonCorrect {
private String name;
private int age;
public PersonCorrect(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PersonCorrect that = (PersonCorrect) o;
return age == that.age &&
Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
// getteri vynechané pre stručnosť
}
// Použitie v kolekcii
List<PersonBroken> brokenList = new ArrayList<>();
brokenList.add(new PersonBroken("Alice", 30));
System.out.println(brokenList.contains(new PersonBroken("Alice", 30))); // Pravdepodobne false
List<PersonCorrect> correctList = new ArrayList<>();
correctList.add(new PersonCorrect("Alice", 30));
System.out.println(correctList.contains(new PersonCorrect("Alice", 30))); // Pravdepodobne true
Set<PersonBroken> brokenSet = new HashSet<>();
brokenSet.add(new PersonBroken("Bob", 25));
brokenSet.add(new PersonBroken("Bob", 25));
System.out.println(brokenSet.size()); // Pravdepodobne 2
Set<PersonCorrect> correctSet = new HashSet<>();
correctSet.add(new PersonCorrect("Bob", 25));
correctSet.add(new PersonCorrect("Bob", 25));
System.out.println(correctSet.size()); // Pravdepodobne 1
V príklade s PersonBroken sú objekty s rovnakými hodnotami polí považované za odlišné v kolekciách, pretože sa používajú predvolené implementácie equals (porovnáva referencie) a hashCode (generuje podľa adresy objektu). V príklade s PersonCorrect umožňujú prepísané metódy kolekciám správne určovať ekvivalentnosť objektov na základe ich obsahu.