Sobes.tech
Middle

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.

  1. Symmetrie: Als a.equals(b) true retourneert, dan moet b.equals(a) ook true zijn.
  2. Reflexiviteit: Voor elk niet-nul object a moet a.equals(a) true zijn.
  3. Transitiviteit: Als a.equals(b) en b.equals(c) true retourneren, dan moet a.equals(c) ook true zijn.
  4. Consistentie: Meerdere aanroepen van a.equals(b) moeten consistent true of false retourneren, tenzij de informatie die in equals-vergelijkingen wordt gebruikt, wordt gewijzigd.

Voor hashCode:

  1. Consistentie: Als de informatie die in equals-vergelijkingen wordt gebruikt, niet is gewijzigd, moeten meerdere aanroepen van hashCode op hetzelfde object hetzelfde gehele getal retourneren.
  2. Relatie met equals: Als twee objecten gelijk zijn volgens de equals-methode, dan moet de hashCode-waarde voor beide hetzelfde zijn.
  3. Optimalisatie: Het is niet nodig dat, als twee objecten niet gelijk zijn volgens equals, de hashCode-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.