Java 显示更多值的哈希集 类密钥管理器{ 公共国际一级; 公钥主机(inti){this.i=i;} 公共布尔等于(对象o){returni==((KeyMaster)o).i;} public int hashCode(){return i;} } 麻省理工学院公共课 { 公共静态void main(字符串[]args){ Set=newhashset(); KeyMaster k1=新的KeyMaster(1); KeyMaster k2=新的KeyMaster(2); 集合。添加(k1); 集合。添加(k1); 增加(k2); 增加(k2); System.out.println(set.size()+“:”); k2.i=1;//这是在HashSet中创建另一个对象 设置。移除(k1); System.out.println(set.size()+“:”); 设置。移除(k2); System.out.print(set.size()); } }

Java 显示更多值的哈希集 类密钥管理器{ 公共国际一级; 公钥主机(inti){this.i=i;} 公共布尔等于(对象o){returni==((KeyMaster)o).i;} public int hashCode(){return i;} } 麻省理工学院公共课 { 公共静态void main(字符串[]args){ Set=newhashset(); KeyMaster k1=新的KeyMaster(1); KeyMaster k2=新的KeyMaster(2); 集合。添加(k1); 集合。添加(k1); 增加(k2); 增加(k2); System.out.println(set.size()+“:”); k2.i=1;//这是在HashSet中创建另一个对象 设置。移除(k1); System.out.println(set.size()+“:”); 设置。移除(k2); System.out.print(set.size()); } },java,hashset,Java,Hashset,我在HashSet中添加了两个对象,并删除了它,但在上一个s.o.p中,我的大小仍然是1。我同意我已经更新了k2的值,但我仍然没有将其添加到我的集合中。k2.I=1没有在HashSet中创建另一个对象,但它更改了k2的哈希代码。这就是为什么set.remove(k2)无法找到并删除k2。如果测试set.remove(k2)返回值,您将看到false,这意味着该对象未被删除。来自HashSet.remove()的Javadoc: 从该集合中删除指定的元素(如果存在)。更正式地说,删除元素e,使得(

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

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

来自
HashSet.remove()的Javadoc:

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

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

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());
}
}
我不确定你认为那里发生了什么,但不是那样

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

它实际上已经找不到了


HashSet.remove()
返回一个
布尔值
-如果要检查该返回值,您会发现它为false。

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

是Java吗?我猜对了吗?@JanDvorak:是的,
System.out.println()
给出了它。“这是在HashSet中创建另一个对象”。。。呃,不,不是。这就是为什么
set.remove(k2)不做任何事情。该类没有
adds
方法(静态或其他)。这是你没有提到的打字错误还是编译时错误?你通过改变HashSet中的元素打破了HashSet的契约。无论从那里发生什么,都取决于实现。该实现允许抛出异常,甚至出于恶意擦除硬盘。顺便问一下,这句话是否意味着鼻魔在Java中是可能的呢。。。可能是的。所以你的意思是,由于我的hashcode现在被更改了,我的remove方法现在找不到k2。@正确。当集合中的元素在集合中时,不应更改集合中的元素。在集合的任何实现中更改元素都不是一个好主意。添加一个附加点,这是建议将不可变对象存储在散列集合中的唯一原因。@JunedAhsan,您能提供关于散列集合对象需要存储为不可变的参考吗?@AlpeshGediya给您:&
k2.i = 1; // this is creating another object in HashSet