更改其字段后从Set中删除对象

时间:2015-02-15 17:58:31

标签: java set hashcode

我在准备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());
    }
}

结果是:2:2:1:1

问题是:为什么在更改k2字段后无法将其删除?

2 个答案:

答案 0 :(得分:3)

HashSet中的对象根据其hashCode()定位。如果更改导致hashCode()更改的字段,Java将无法在集合中找到它,因此无法将其删除。

答案 1 :(得分:2)

如果您想象HashSet如何运作,那么它就变得显而易见了。

假设您有HashSet仅允许01哈希码值,它有两个存储桶:

  • 1
  • 0

add项目HashSet时,HashSet会确定hashCode1还是0并找到正确的桶。

因此,您可以创建对象thingsetHashCode(1)以及addHashSet获取hashCode并将其正式转储到1广告管理中。

如何拨打thing.setHashCode(0)然后remove。怎么了?好吧,HashSet获得了hashCode thing0。它会在0存储桶中查找,但当您将add thing调用时,1被置于存储桶HashSet中,HashSet会查找错误的存储桶< / strong>即可。 thing无法找到add来删除它。

有趣的是,如果thing2 hashCode 0equals。如果hashCode == other.hashCode已实施(如您的示例中)remove(thing),那么在将hashCode thing设置为0后调用thing2将会实际上删除 Object

这是一个很好的示例,说明如果equalshashCodeObjectMap属性中Set的属性使用的原因不应该更改用作{{1}}密钥或放入{{1}}。