Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 更改对象字段后从集合中删除对象_Java_Set_Hashcode - Fatal编程技术网

Java 更改对象字段后从集合中删除对象

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

我在准备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 {
    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
属性中使用的属性