0
class KeyMaster {
  public int i;
  public KeyMaster(int i) { this.i = i; }
  public boolean equals(Object o) { return i == ((KeyMaster)o).i; }
  public int hashCode() { return i; }
}


public class MIt 
{
 public static void main(String[] args) {
  Set<KeyMaster> set = new HashSet<KeyMaster>();
  KeyMaster k1 = new KeyMaster(1);
  KeyMaster k2 = new KeyMaster(2);
  set.add(k1); 
  set.add(k1);
  set.add(k2); 
  set.add(k2);
  System.out.println(set.size()+":");

  k2.i = 1; // this is creating another object in HashSet
  set.remove(k1);
  System.out.println(set.size()+":");
  set.remove(k2);
  System.out.print(set.size());
}
}

我已经向 HashSet 添加了两个对象并将其删除,但在最后一个 sop 中我仍然有大小 1。我同意我已经更新了 k2 的值,但我仍然没有将它添加到我的集合中。

4

3 回答 3

3

来自 Javadoc 的HashSet.remove()

如果存在,则从此集合中删除指定的元素。更正式地说,删除元素 e 使得 (o==null ? e==null : o.equals(e))

您的代码中有一行注释,上面写着:

k2.i = 1; // this is creating another object in HashSet

我不确定你认为那里发生了什么,但事实并非如此。

k2是对您放入HashSet. 您刚刚更改了i该对象中的值,您在重写equals()hashcode()方法中使用了该值。当您谈论涉及哈希的任何事情以及为什么您真的不应该使用可变对象作为键时,这是一件非常糟糕的事情。

从字面上看,它再也找不到了。

HashSet.remove()返回 a boolean- 如果您要检查该返回值,您会发现它是错误的。

于 2013-05-04T04:59:08.053 回答
3

Hashset 使用散列来存储和检索对象。当我们在 hashmap 中添加一个对象时,JVM 会查找 hashcode 实现来决定将对象放在内存中的哪个位置。当我们再次检索对象时,哈希码用于获取对象的位置。如果在将对象插入到 hashmap 后更改它,则更新后的对象将具有与最初存储的对象不同的 hashcode。就像您更新 k2.i=1 时的情况一样,k2 的哈希码现在将与原始 k2 对象不同。因此,当您使用更新的 k2 调用 remove 时,JVM 实际上找不到该对象,因此无法删除。这就是为什么你在上一个 sop 中看到 size 为 1 的原因

于 2013-05-04T05:12:37.347 回答
2

k2.i = 1;不是在 HashSet 中创建另一个对象,而是改变了 k2 的哈希码。这就是为什么set.remove(k2);无法找到并删除 k2。如果您测试set.remove(k2)返回值,您将看到 false,这意味着该对象未被删除。

于 2013-05-04T04:56:21.723 回答