Middle
Почему важно переопределять методы equals и hashCode в Java?
sobes.tech AI
Answer from AI
Overriding equals and hashCode is important for correct object handling in collections and comparisons.
- Symmetry: If
a.equals(b)returnstrue, thenb.equals(a)should also betrue. - Reflexivity: For any non-null object
a,a.equals(a)should betrue. - Transitivity: If
a.equals(b)andb.equals(c)returntrue, thena.equals(c)should also betrue. - Consistency: Multiple invocations of
a.equals(b)should consistently returntrueorfalse, provided no information used inequalscomparisons on the objects is modified.
For hashCode:
- Consistency: If the information used in
equalscomparisons on the object has not been changed, multiple calls tohashCodeon the object should return the same integer value. - Relation to
equals: If two objects are equal according to theequalsmethod, then callinghashCodeon each of the unequal objects should return the same integer value. - Optimization: It is not required that if two objects are unequal according to
equals, then callinghashCodeon each of the unequal objects should produce different integer results. However, generating different hash codes for unequal objects can improve hash table performance.
Violating these rules leads to unpredictable behavior when using collections such as HashSet, HashMap, ArrayList, and others that rely on the correct implementation of these methods for proper object equality determination and placement.
For example:
// Example of a class without correct `equals` and `hashCode`
class PersonBroken {
private String name;
private int age;
public PersonBroken(String name, int age) {
this.name = name;
this.age = age;
}
// getters omitted for brevity
}
// Example of a class with correct `equals` and `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 omitted for brevity
}
// Usage in collections
List<PersonBroken> brokenList = new ArrayList<>();
brokenList.add(new PersonBroken("Alice", 30));
System.out.println(brokenList.contains(new PersonBroken("Alice", 30))); // Likely false
List<PersonCorrect> correctList = new ArrayList<>();
correctList.add(new PersonCorrect("Alice", 30));
System.out.println(correctList.contains(new PersonCorrect("Alice", 30))); // Likely true
Set<PersonBroken> brokenSet = new HashSet<>();
brokenSet.add(new PersonBroken("Bob", 25));
brokenSet.add(new PersonBroken("Bob", 25));
System.out.println(brokenSet.size()); // Likely 2
Set<PersonCorrect> correctSet = new HashSet<>();
correctSet.add(new PersonCorrect("Bob", 25));
correctSet.add(new PersonCorrect("Bob", 25));
System.out.println(correctSet.size()); // Likely 1
In the PersonBroken example, objects with identical field values are considered different in collections because the default equals (reference comparison) and hashCode (address-based) implementations are used. In the PersonCorrect example, overridden methods allow collections to correctly determine object equivalence based on their content.