Sobes.tech
Middle

Kāpēc ir svarīgi pārrakstīt metodes equals un hashCode Java?

sobes.tech AI

Atbilde no AI

equals un hashCode metožu pārrakstīšana ir svarīga, lai pareizi darbotos ar objekti kolekcijās un salīdzināšanā.

  1. Simetrija: Ja a.equals(b) atgriež true, tad b.equals(a) arī jābūt true.
  2. Refleksivitāte: Katram nevainojamam objektam a, jābūt a.equals(a) true.
  3. Transitivitāte: Ja a.equals(b) un b.equals(c) abi atgriež true, tad arī a.equals(c) jābūt true.
  4. Saskaņotība: Daudzkārtēji a.equals(b) izsaukumi konsekventi atgriež true vai false, ja objektiem izmantotā informācija nav mainījusies.

hashCode:

  1. Saskaņotība: Ja informācija, kas tiek izmantota equals salīdzinājumā, nav mainījusies, vairāki hashCode izsaukumi uz objekta jāatgriež to pašu veselo skaitli.
  2. Saistība ar equals: Ja divi objekti ir vienādi pēc equals, tad to hashCode izsaukumi jāatgriež to pašu skaitlisko vērtību.
  3. Optimizācija: Nav nepieciešams, lai ja divi objekti nav vienādi pēc equals, to hashCode izsaukumi atgrieztu dažādus skaitļus. Tomēr dažādu hashCode ģenerēšana var uzlabot hash tabulu veiktspēju.

Šo noteikumu pārkāpšana noved pie neparedzama uzvedības, izmantojot kolekcijas, piemēram, HashSet, HashMap, ArrayList un citus, kas balstās uz šo metožu pareizu īstenošanu objektiem, lai pareizi noteiktu vienādību un izvietojumu.

Piemēram:

// Klase bez pareizi pārdefinētiem `equals` un `hashCode`
class PersonBroken {
    private String name;
    private int age;

    public PersonBroken(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // getters izlaisti
}

// Klase ar pareizi pārdefinētiem `equals` un `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 izlaisti
}

// Kolekcijas izmantošana
List<PersonBroken> brokenList = new ArrayList<>();
brokenList.add(new PersonBroken("Alice", 30));
System.out.println(brokenList.contains(new PersonBroken("Alice", 30))); // Iespējams, false

List<PersonCorrect> correctList = new ArrayList<>();
correctList.add(new PersonCorrect("Alice", 30));
System.out.println(correctList.contains(new PersonCorrect("Alice", 30))); // Iespējams, true

Set<PersonBroken> brokenSet = new HashSet<>();
brokenSet.add(new PersonBroken("Bob", 25));
brokenSet.add(new PersonBroken("Bob", 25));
System.out.println(brokenSet.size()); // Iespējams, 2

Set<PersonCorrect> correctSet = new HashSet<>();
correctSet.add(new PersonCorrect("Bob", 25));
correctSet.add(new PersonCorrect("Bob", 25));
System.out.println(correctSet.size()); // Iespējams, 1

PersonBroken piemērs, objekti ar vienādām lauku vērtībām tiek uzskatīti par dažādiem kolekcijās, jo tiek izmantotas noklusējuma equals (salīdzina atsauces) un hashCode (ģenerē pēc objekta adreses). PersonCorrect piemērs ar pārdefinētām metodēm ļauj kolekcijām pareizi noteikt objektu ekvivalenci pēc to satura.