Reputation: 4564
I have found this question during my preparation for SCJP:
class Key {
public int i;
public Key(int i) {
this.i = i;
}
public boolean equals(Object o) {
return i == ((Key) o).i;
}
public int hashCode() {
return i;
}
}
public class Test {
public static void main(String[] args) {
Set<Key> set = new HashSet<Key>();
Key k1 = new Key(1);
Key k2 = new Key(2);
set.add(k1);
set.add(k1);
set.add(k2);
set.add(k2);
System.out.print(set.size() + “:”);
k2.i = 1;
System.out.print(set.size() + “:”);
set.remove(k1);
System.out.print(set.size() + “:”);
set.remove(k2);
System.out.print(set.size());
}
}
the result is: 2:2:1:1
.
The question is: why after changing the field of k2
can't it be removed?
Upvotes: 1
Views: 111
Reputation: 61148
If you imagine how a HashSet
works, then it becomes obvious.
Lets say you have a HashSet
that only allows 0
or 1
hashcode values, it has two buckets:
1
0
When you add
an item to the HashSet
, the HashSet
works out whether the hashCode
is 1
or 0
and finds the correct bucket.
So you create your object thing
and setHashCode(1)
, and add
it. The HashSet
gets the hashCode
and duly dumps it into the 1
bucket.
How you call thing.setHashCode(0)
and then remove
. What happens? Well, the HashSet
gets the hashCode
of thing
, it's 0
. It looks in the 0
bucket, but when you called add
thing
was put into bucket 1
- the HashSet
looks in the wrong bucket. The HashSet
cannot find thing
to remove it.
Interestingly, if you add
thing2
with a hashCode
of 0
. And if you equals
is implemented (as in your example) as hashCode == other.hashCode
, then calling remove(thing)
after setting hashCode
of thing
to 0
will actually remove thing2
.
This is a good example of why the properties of an Object
use in it's equals
and hashCode
properties should not be changed if the Object
is used as a Map
key or placed into a Set
.
Upvotes: 2
Reputation: 311218
An object in a HashSet
is located according to its hashCode()
. If you change a field that causes the hashCode()
to change, Java would be unable to locate it in the set, and thus unable to remove it.
Upvotes: 3