Waarom is het belangrijk om de methods equals en hashCode in Java te overschrijven?
sobes.tech AI
Antwoord van AI
Het overschrijven van equals en hashCode is belangrijk voor het correct werken met objecten in collecties en bij vergelijking.
- Symmetrie: Als
a.equals(b)trueretourneert, dan moetb.equals(a)ooktruezijn. - Reflexiviteit: Voor elk niet-nul object
amoeta.equals(a)truezijn. - Transitiviteit: Als
a.equals(b)enb.equals(c)trueretourneren, dan moeta.equals(c)ooktruezijn. - Consistentie: Meerdere aanroepen van
a.equals(b)moeten consistenttrueoffalseretourneren, tenzij de informatie die inequals-vergelijkingen wordt gebruikt, wordt gewijzigd.
Voor hashCode:
- Consistentie: Als de informatie die in
equals-vergelijkingen wordt gebruikt, niet is gewijzigd, moeten meerdere aanroepen vanhashCodeop hetzelfde object hetzelfde gehele getal retourneren. - Relatie met
equals: Als twee objecten gelijk zijn volgens deequals-methode, dan moet dehashCode-waarde voor beide hetzelfde zijn. - Optimalisatie: Het is niet nodig dat, als twee objecten niet gelijk zijn volgens
equals, dehashCode-aanroep op elk van hen verschillende resultaten oplevert. Het genereren van verschillende hash-codes voor niet-gelijke objecten kan echter de prestaties van hash-tabellen verbeteren.
Het niet naleven van deze regels leidt tot onvoorspelbaar gedrag bij het gebruik van collecties zoals HashSet, HashMap, ArrayList en andere, die afhankelijk zijn van een correcte implementatie van deze methoden om de gelijkheid van objecten en hun plaatsing correct te bepalen.
Bijvoorbeeld:
// Voorbeeldklasse zonder correcte `equals` en `hashCode`
class PersonBroken {
private String name;
private int age;
public PersonBroken(String name, int age) {
this.name = name;
this.age = age;
}
// getters weggelaten voor beknoptheid
}
// Voorbeeldklasse met correcte `equals` en `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);
}
// getters weggelaten voor beknoptheid
}
// Gebruik in collectie
List<PersonBroken> brokenList = new ArrayList<>();
brokenList.add(new PersonBroken("Alice", 30));
System.out.println(brokenList.contains(new PersonBroken("Alice", 30))); // Waarschijnlijk false
List<PersonCorrect> correctList = new ArrayList<>();
correctList.add(new PersonCorrect("Alice", 30));
System.out.println(correctList.contains(new PersonCorrect("Alice", 30))); // Waarschijnlijk true
Set<PersonBroken> brokenSet = new HashSet<>();
brokenSet.add(new PersonBroken("Bob", 25));
brokenSet.add(new PersonBroken("Bob", 25));
System.out.println(brokenSet.size()); // Waarschijnlijk 2
Set<PersonCorrect> correctSet = new HashSet<>();
correctSet.add(new PersonCorrect("Bob", 25));
correctSet.add(new PersonCorrect("Bob", 25));
System.out.println(correctSet.size()); // Waarschijnlijk 1
In het voorbeeld met PersonBroken worden objecten met dezelfde veldwaarden als verschillend beschouwd in collecties, omdat de standaardimplementaties van equals (vergelijking van referenties) en hashCode (gegenereerd op basis van het objectadres) worden gebruikt. In het voorbeeld met PersonCorrect zorgen de overschreven methoden ervoor dat collecties de gelijkwaardigheid van objecten op basis van hun inhoud correct kunnen bepalen.