Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.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 对于插入后修改的实例,HashSet.contains(对象)返回false_Java_Collections_Hashset - Fatal编程技术网

Java 对于插入后修改的实例,HashSet.contains(对象)返回false

Java 对于插入后修改的实例,HashSet.contains(对象)返回false,java,collections,hashset,Java,Collections,Hashset,根据所述方法,执行以下操作 如果此集合包含指定的元素,则返回true。更多 形式上,当且仅当该集合包含元素e时,返回true 这样(o==null?e==null:o.equals(e)) 但是,这似乎不适用于以下代码: public static void main(String[] args) { HashSet<DemoClass> set = new HashSet<DemoClass>(); DemoClass toInsert = new De

根据所述方法,执行以下操作

如果此集合包含指定的元素,则返回true。更多 形式上,当且仅当该集合包含元素e时,返回true 这样(o==null?e==null:o.equals(e))

但是,这似乎不适用于以下代码:

public static void main(String[] args) {
    HashSet<DemoClass> set = new HashSet<DemoClass>();
    DemoClass toInsert = new DemoClass();
    toInsert.v1 = "test1";
    toInsert.v2 = "test2";
    set.add(toInsert);
    toInsert.v1 = null;

    DemoClass toCheck = new DemoClass();
    toCheck.v1 = null;
    toCheck.v2 = "test2";

    System.out.println(set.contains(toCheck));
    System.out.println(toCheck.equals(toInsert));
}

private static class DemoClass {
    String v1;
    String v2;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((v1 == null) ? 0 : v1.hashCode());
        result = prime * result + ((v2 == null) ? 0 : v2.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        DemoClass other = (DemoClass) obj;
        if (v1 == null) {
            if (other.v1 != null)
                return false;
        } else if (!v1.equals(other.v1))
            return false;
        if (v2 == null) {
            if (other.v2 != null)
                return false;
        } else if (!v2.equals(other.v2))
            return false;
        return true;
    }

}
publicstaticvoidmain(字符串[]args){
HashSet=newhashset();
DemoClass toInsert=新建DemoClass();
toInsert.v1=“test1”;
toInsert.v2=“test2”;
set.add(toInsert);
toInsert.v1=null;
DemoClass toCheck=新建DemoClass();
toCheck.v1=null;
toCheck.v2=“test2”;
System.out.println(set.contains(toCheck));
System.out.println(toCheck.equals(toInsert));
}
私有静态类DemoClass{
字符串v1;
字符串v2;
@凌驾
公共int hashCode(){
最终整数素数=31;
int结果=1;
result=prime*result+((v1==null)?0:v1.hashCode();
result=prime*result+((v2==null)?0:v2.hashCode();
返回结果;
}
@凌驾
公共布尔等于(对象obj){
if(this==obj)
返回true;
if(obj==null)
返回false;
如果(getClass()!=obj.getClass())
返回false;
DemoClass其他=(DemoClass)obj;
如果(v1==null){
如果(other.v1!=null)
返回false;
}else如果(!v1.equals(other.v1))
返回false;
如果(v2==null){
如果(other.v2!=null)
返回false;
}如果(!v2.equals(other.v2))
返回false;
返回true;
}
}
打印出:

假的

真的

因此,尽管
equals
方法返回
true
HashSet.contains()
返回
false

我猜这是因为我在将toInsert实例添加到集合后修改了它


然而,这是没有任何方式记录(或至少我无法找到这样的)。此外,还应使用上述equals方法引用的文档,但似乎并非如此。

HashSet
HashMap
使用
hashCode
equals
方法在其内部结构中定位对象
hashCode
用于查找正确的bucket,然后参考
equals
来区分具有相同hashCode的不同对象,因为后者不能保证是唯一的。几乎在任何情况下,修改对象都是一个非常糟糕的主意,该对象在
HashMap
中充当键,或者被放入
HashSet
中。如果这些修改更改了hashCode或
equals
方法的语义,将找不到您的对象。

很明显,在添加到集合后,您正在将
更改为insert.v1
,并且由于
DemoClass
v1
v2
属性中获取hashCode,它找不到元素的已更改哈希代码。

这是由设计行为决定的

HashSet
使用哈希来识别它所持有的对象

因此,如果在将对象放入集合后更改该对象,它可能无法找到该对象

您应该只保存不可变对象,或者只使对象的该部分可变,这不会影响哈希


我认为最好使用
HashMap
,它清楚地将可变部分和不可变部分分开。

当一个对象存储在
HashSet
中时,它将被放入一个数据结构中,该数据结构可以被对象的
hashCode()
轻松(高效地)搜索。修改对象可能会更改其
hashCode()
(取决于您如何实现它),但不会更新其在
HashSet
中的位置,因为对象无法知道其包含在其中

你可以在这里做几件事:

  • 修改
    hashCode()
    的实现,使其不受所更改字段的影响。假设此字段对对象的状态很重要,并且参与了
    equals(object)
    方法,这有点像代码味道,可能应该避免

  • 在修改对象之前,请将其从集合中删除,然后在完成修改后重新添加:


  • Set mySet=。。。;
    DemoClass演示=。。。;
    布尔值wasInSet=mySet.remove(演示);
    demo.setV1(“新v1”);
    demo.setV2(“新v2”);
    如果(插图){
    set.add(演示);
    }
    
    您更改了哈希值,哈希值被哈希集记住,因此无法识别对象。可能是的重复项
    Set<DemoClass> mySet = ...;
    DemoClass demo = ...;
    boolean wasInSet = mySet.remove(demo);
    demo.setV1("new v1");
    demo.setV2("new v2");
    if (wasInSet) {
        set.add(demo);
    }