import java.util.*;
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 MapIt {
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.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
但预期产出
2
2
1
0
答案 0 :(得分:3)
您必须了解HashSet
的工作原理。
当你这样做时:
KeyMaster k = new KeyMaster(1);
set.add(k);
HashSet
获取k
对象的哈希码,并将此哈希码与对象关联。在这种情况下,k
将与1
相关联。
现在您正在通过
更改k
值
k.i = 2;
k
对象的值已更改,但HashSet
此对象仍与1
关联,因为HashSet
已记住以前的哈希码。
因此,当您尝试从k
HashSet
时
set.remove(k);
HashSet
将获得k
的哈希码。如您所知,哈希码已更改,它将为2
,但在HashSet
中,我们的对象仍与哈希码1
相关联。这就是HashSet
无法找到并删除此对象的原因。
实际上,在对象添加到HashSet之后更改哈希代码是不好的做法。
答案 1 :(得分:2)
当k2.i = 1;
并在set.remove(k2);
之后执行时会尝试消除值1和2的元素,因此最终大小将始终为1。
答案 2 :(得分:0)
输出仍为2 2 1 1
您要覆盖equals()
和hashcode()
两种方法。
首先Sysout
打印尺寸2
,包含两个项目。
第二个Sysout
打印尺寸2
,而不是从集合中删除任何项目。
第三个Sysout
打印尺寸1
,删除k1
已存在且值为1
。
第四个Sysout
打印尺寸1
,删除不存在的k2
k2.i = 1
。
修改强>
尝试删除k2
k2.i = 2;
,因为它存在。然后,您将看到预期的输出为2 2 1 0
。
答案 3 :(得分:0)
HashSet
(或HashMap
)被组织为一系列&#34;桶&#34;其中每个桶包含一组值。当你是哈希的对象时,它将计算哈希码H,从H确定桶号(通常是H mod some-number),并将对象放入该桶中。
假设哈希码为1并且对象放入存储桶1.现在假设您执行某些操作(如更改k2.i
),这会更改哈希码的值。 这不会导致将对象移动到其他存储桶。(它不能,因为没有办法设置&#34;触发器&#34; on一个字段赋值,它会导致HashSet
重新评估哈希码。)现在,当你尝试进行操作时,HashSet
类将计算新的哈希码,但是对象现在在错误的桶。所以班级找不到对象。
基本上,以更改哈希代码的方式更改对象将完全搞砸对象所属的任何HashSet
或HashMap
。 永远不要那样做。