Should hashCode () use only a subset of the immutable fields of those used in equals ()?

Situation

I needed to overwrite equals(), and as recommended, I also overwrite the method hashCode()using the same fields. Then, when I looked at a set containing only one object, I got a disappointing result

set.contains(object)
=> false

and

set.stream().findFirst().get().equals(object)
=> true

Now I understand that this is due to changes made to objectafter it was added to set, which again changed its hashCode. containsthen it looks through the wrong key and cannot find it object.

My implementation requirements:

  • For correct implementation
equals()mutable fields are needed to safely use these objects in hash-based Collectionsor Mapssuch ashes HashSet, even if they are subject to change.

which conflicts with the agreement that

Question

Are there any dangers for using only the subset of the fields that are used equals()to calculate hashCode()instead of using all?

More specifically, this would mean: it equals()uses several fields of the object, while it hashCode()uses only those fields that are used in and which are immutable . equals()

I think it should be good, because

  • : -, hashCode , .
  • - , HashSet .

, , : hashCode Java? equals hashcode

+4
4

. , .equal() .hashCode(). , , IDE . , -.

BTW, IntelliJ hashCode , . , , hashCode() equals(), .

0

HashSet / : hashCode() equals(). , , - .

, , , TreeSet. , ( ) "" , , . equals() , , :

  • compareTo() , .
  • compareTo() TreeSet.

.

0

. , Person:

 final int name; // used in hashcode
 int income; // name + income used in equals

name , ( HashMap) .

Person Key HashMap: hashcode , , . income Person . hashcode , equals :

 static class Person {
    private final String name;

    private int income;

    public Person(String name) {
        super();
        this.name = name;
    }

    public int getIncome() {
        return income;
    }

    public void setIncome(int income) {
        this.income = income;
    }

    public String getName() {
        return name;
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }

    @Override
    public boolean equals(Object other) {
        Person right = (Person) other;

        return getIncome() == right.getIncome() && getName().equals(right.getName());
    }

}

:

    HashSet<Person> set = new HashSet<>();
    Person bob = new Person("bob");
    bob.setIncome(100);
    set.add(bob);

    Person sameBob = new Person("bob");
    sameBob.setIncome(200);

    System.out.println(set.contains(sameBob)); // false

, , , , hashcode , ( ), , equals , , .

, , ; , , - hashcode, .

, - , , ( ) equal - .

0

hashCode() , equals(), .

, , , , , hashCode() / equals(). , HashSet ( HashMap), , equals() / hashCode(). , equals(), final. , , , .

TreeSet/TreeMap, , compareTo().

If you really need to change the fields that are used equals()(or compareTo()in the case of TreeSet / TreeMap), you should:

  • First remove this object from the set;
  • Then modify the object;
  • And finally, add it back to the set.
0
source

Source: https://habr.com/ru/post/1685875/


All Articles