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的值但是我还没有将它添加到我的集合中。
答案 0 :(得分:3)
来自HashSet.remove()
的Javadoc:
从该集合中删除指定的元素(如果存在)。更正式地,删除元素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()
返回boolean
- 如果要检查返回值,则会发现它是错误的。
答案 1 :(得分:3)
Hashset使用散列来存储和检索对象。当我们在hashmap中添加一个对象时,JVM会查找hashcode实现来决定将对象放在内存中的位置。当我们再次检索对象时,hashcode用于获取对象的位置。如果在将对象插入到散列映射后更改对象,则更新的对象将具有与最初存储的对象不同的散列码。在您更新k2.i = 1的情况下,k2的哈希码现在将与原始k2对象不同。因此,当您使用更新的k2调用remove时,JVM实际上找不到该对象,因此无法删除。这就是你在上一次s.o.p
中看到大小为1的原因答案 2 :(得分:2)
k2.i = 1;
没有在HashSet中创建另一个对象,但它改变了k2的哈希码。这就是set.remove(k2);
无法找到并删除k2的原因。如果您测试set.remove(k2)
返回值,您将看到false,表示该对象未被删除。