Java 更改对象字段后从集合中删除对象
我在准备SCJP时发现了这个问题:Java 更改对象字段后从集合中删除对象,java,set,hashcode,Java,Set,Hashcode,我在准备SCJP时发现了这个问题: class Key { public int i; public Key(int i) { this.i = i; } public boolean equals(Object o) { return i == ((Key) o).i; } public int hashCode() { return i; } } public class Test
class Key {
public int i;
public Key(int i) {
this.i = i;
}
public boolean equals(Object o) {
return i == ((Key) o).i;
}
public int hashCode() {
return i;
}
}
public class Test {
public static void main(String[] args) {
Set<Key> set = new HashSet<Key>();
Key k1 = new Key(1);
Key k2 = new Key(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());
}
}
类密钥{
公共国际一级;
公钥(int i){
这个。i=i;
}
公共布尔等于(对象o){
返回i==((键)o).i;
}
公共int hashCode(){
返回i;
}
}
公开课考试{
公共静态void main(字符串[]args){
Set=newhashset();
键k1=新键(1);
键k2=新键(2);
集合。添加(k1);
集合。添加(k1);
增加(k2);
增加(k2);
System.out.print(set.size()+“:”);
k2.i=1;
System.out.print(set.size()+“:”);
设置。移除(k1);
System.out.print(set.size()+“:”);
设置。移除(k2);
System.out.print(set.size());
}
}
结果是:2:2:1:1
问题是:为什么在更改了
k2
的字段后不能将其删除?哈希集中的对象根据其hashCode()
进行定位。如果更改导致hashCode()
更改的字段,Java将无法在集合中找到它,因此无法删除它。HashSet中的对象根据其hashCode()
进行定位。如果您更改一个导致hashCode()
更改的字段,Java将无法在集合中找到它,因此无法删除它。如果您想象HashSet
是如何工作的,那么它就变得显而易见了
假设您有一个只允许0
或1
哈希值的HashSet
,它有两个bucket:
1
0
向哈希集
添加一个项目时,哈希集
会计算出哈希码
是1
还是0
,并找到正确的bucket
因此,您可以创建对象thing
和setHashCode(1)
,然后添加它。HashSet
获取hashCode
并将其适当地转储到1
存储桶中
如何调用东西。setHashCode(0)
然后删除
。会发生什么?嗯,HashSet
获取thing
的hashCode
,它是0
。它在0
存储桶中查找,但当您调用add
时,thing
被放入存储桶1
,HashSet
在错误的存储桶中查找。HashSet
无法找到对象来删除它
有趣的是,如果您使用hashCode
的0
添加内容2
。如果将equals
实现为hashCode==other.hashCode
,则在将thing
的hashCode
设置为0
后调用remove(thing)
,实际上将删除thing2
这是一个很好的例子,说明了如果对象被用作映射
键或放入集合
中,那么对象在其等于
和hashCode
属性中使用的属性不应该更改。如果您想象HashSet
是如何工作的,那么它就变得显而易见了
假设您有一个只允许0
或1
哈希值的HashSet
,它有两个bucket:
1
0
当您向哈希集
添加一个项目时,哈希集
会计算出哈希码
是1
还是0
,并找到正确的bucket
因此,您可以创建对象thing
和setHashCode(1)
,然后添加它。HashSet
获取hashCode
并将其适当地转储到1
存储桶中
如何调用东西。setHashCode(0)
然后删除
。会发生什么?嗯,HashSet
获取thing
的hashCode
,它是0
。它在0
存储桶中查找,但当您调用add
时,thing
被放入存储桶1
,HashSet
在错误的存储桶中查找。HashSet
无法找到对象来删除它
有趣的是,如果您使用hashCode
的0
添加内容2
。如果将equals
实现为hashCode==other.hashCode
,则在将thing
的hashCode
设置为0
后调用remove(thing)
,实际上将删除thing2
这是一个很好的例子,说明了如果对象
用作映射
键或放置在集合
中,则不应更改对象
在其equals
和hashCode
属性中使用的属性