Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Contains" implementation of ArrayList vs HashSet

I have a HashSet<Foo>. I have an object that is

  1. equal to an element of the collection and
  2. has a matching hashcode to the same object of the implementation.

Still if I call hashSet.contains(fooInstance) it returns false.

Where it gets really weird is that the following line returns true:

new ArrayList<Foo>(hashSet).contains(fooInstance)

Sadly it turned out harder than expected to find out where exactly is the difference of the .contains() implementation. But I thought I would be safe, since .equals() and .hashCode() work fine.

like image 411
fancy Avatar asked Jan 12 '23 08:01

fancy


1 Answers

The most likely reason is that the hashCode of Foo is not stable and that the return value of hashCode() of the Foo instance changed after it was added to the HashSet. Ideally, you would only ever add immutable objects to a HashSet.

For performance reasons the HashSet stores the calculated hashCode in its entry, so that it doesn't need to re-calculate it for each get. So if the object changes while inside the HashSet, this won't be realized and your object will effectively be "lost" in the HashSet (you can still get it, by iterating over all elements, which is essentially what copying into an ArrayList does).

like image 57
Joachim Sauer Avatar answered Jan 21 '23 13:01

Joachim Sauer