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ā.
- Simetrija: Ja
a.equals(b)atgriežtrue, tadb.equals(a)arī jābūttrue. - Refleksivitāte: Katram nevainojamam objektam
a, jābūta.equals(a)true. - Transitivitāte: Ja
a.equals(b)unb.equals(c)abi atgriežtrue, tad arīa.equals(c)jābūttrue. - Saskaņotība: Daudzkārtēji
a.equals(b)izsaukumi konsekventi atgriežtruevaifalse, ja objektiem izmantotā informācija nav mainījusies.
hashCode:
- Saskaņotība: Ja informācija, kas tiek izmantota
equalssalīdzinājumā, nav mainījusies, vairākihashCodeizsaukumi uz objekta jāatgriež to pašu veselo skaitli. - Saistība ar
equals: Ja divi objekti ir vienādi pēcequals, tad tohashCodeizsaukumi jāatgriež to pašu skaitlisko vērtību. - Optimizācija: Nav nepieciešams, lai ja divi objekti nav vienādi pēc
equals, tohashCodeizsaukumi atgrieztu dažādus skaitļus. Tomēr dažāduhashCodeģ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.