Changing elements in a set changes the semantics of 'equals'

Imagine we have this piece of code.

public class HashAddAfter { private class A { public int value; public A(int value) { this.value = value; } public void setValue(int value) { this.value = value; } // Code for hashCode()... // Code for equals()... } Set<A> list1 = new HashSet<A>(); Set<A> list2 = new HashSet<A>(); public static void main(String[] args) { HashAddAfter x = new HashAddAfter(); A e1 = x.new A(1); A e2 = x.new A(1); x.list1.add(e1); x.list2.add(e2); System.out.println(x.list1.equals(x.list2)); // true e1.setValue(4); e2.setValue(4); System.out.println(x.list1.equals(x.list2)); // false } } 

I did not put the code for hashCode () and equals () due to space limitations, but this is the one that was created from Eclipse.

The problem is that before changing the elements in the two sets, the sets are equal. After changing their values ​​(each by the same value), the sets are no longer equal, although e1.hashCode () == e2.hashCode () and e1.equals (e2).

I assume that when comparing two HashSets, Java uses the source hash code of the element (the one that is at the time of insertion). Thus, changing elements after insertion changes the original hash code and therefore contains () returns false.

In my opinion, this is a very unintuitive behavior.

What do you think?

+3
source share
1 answer

This is exactly the expected behavior. For the implementation of Set there is no way to understand that the hashCode element of an element has changed, so it can not do anything to protect against this possibility.

From Set Javadoc :

Note. Great care should be taken if mutable objects are used as specified elements. The behavior of the set is not indicated if the value of the object changes in a way that affects equal comparisons when the object is an element in the set. A special case of this prohibition is that it is unacceptable for the set to contain itself as an element.

+2
source

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


All Articles