jarosik
jarosik

Reputation: 4564

Remove object from Set after changing its field

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

Answers (2)

Boris the Spider
Boris the Spider

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

Mureinik
Mureinik

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

Related Questions