代码中的混乱

时间:2016-01-30 05:00:55

标签: java set

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

4 个答案:

答案 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类将计算新的哈希码,但是对象现在在错误的桶。所以班级找不到对象。

基本上,以更改哈希代码的方式更改对象将完全搞砸对象所属的任何HashSetHashMap永远不要那样做。