Java 如何生成集合的哈希以确保完整性?

Java 如何生成集合的哈希以确保完整性?,java,hash,set,Java,Hash,Set,也许以前有人问过这个问题(我在哪里找不到它) 我有一个aprox的java.util.Set。五万串。我想生成某种散列来检查它是否已更改(比较集合的两个版本的散列) 如果集合更改,则哈希必须不同 如何才能做到这一点?谢谢 编辑: 对不起,这句话有误导性。我不想检查“it”是否已更改(同一实例)。相反,我想检查生成一组字符串的两个(可能相同)实例的两个数据库查询是否相等。我会尝试使用java.util.AbstractSet的hashCode方法,如文档中所述: 返回此集合的哈希代码值。集合的哈希

也许以前有人问过这个问题(我在哪里找不到它)

我有一个aprox的
java.util.Set
。五万串。我想生成某种散列来检查它是否已更改(比较集合的两个版本的散列)

如果集合更改,则哈希必须不同

如何才能做到这一点?谢谢

编辑:

对不起,这句话有误导性。我不想检查“it”是否已更改(同一实例)。相反,我想检查生成一组字符串的两个(可能相同)实例的两个数据库查询是否相等。

我会尝试使用
java.util.AbstractSet
hashCode
方法,如文档中所述:

返回此集合的哈希代码值。集合的哈希代码是 定义为集合中元素的哈希代码之和, 其中空元素的哈希代码定义为零。这 确保s1.equals(s2)表示s1.hashCode()==s2.hashCode() 对于任何两套s1和s2,根据工程总合同的要求 Object.hashCode()

当然,这只有在
实现从
抽象集
扩展时才有效,我想您应该使用例如
java.util.HashSet
与往常一样,存在哈希冲突的可能性。

或者,您可以扩展现有的
实现并覆盖状态更改方法,如果每个对象的哈希计算变得过于昂贵,这可能是有意义的,例如:

class ChangeSet<E> extends java.util.HashSet<E> {
    private boolean changed = false;

    @Override
    public boolean add(E e) {
        changed = true;
        super.add(e);
    }

    public void commit() {
        changed = false;
    }

    public boolean isChanged() {
        return changed;
    }

    /* and all the other methods (addAll, remove, removeAll, etc.) */

}
类变更集扩展了java.util.HashSet{
私有布尔值更改=false;
@凌驾
公共布尔加法(E){
更改=正确;
增订(e);
}
公共无效提交(){
更改=错误;
}
公共布尔值isChanged(){
回报发生变化;
}
/*以及所有其他方法(addAll、remove、removeAll等)*/
}

有时候越简单越好。我建议您编写自己的
Set
实现。在其中,重写
add
remove
方法,以便在修改
set
时设置标志。为标志添加一个getter,
isModified
,这样就不必担心哈希开销或冲突。只需调用
MyCustomSet.isModified


或者,您可以调用
Collections.unmodifiableSet
,在
集合
周围获得一个无法修改的包装器。如果代码试图修改集合,将引发异常。

基于此语句:

如果集合更改,哈希值必须不同

除非你有更多的限制,否则它真的无法实现。通常,散列是某个固定空间中的值。例如,您的哈希可能是32位整数,因此有2^32个可能的哈希值。一般来说,b位可以得到2^b个可能的散列值。为了实现您想要的,您必须确保每个可能的集合(即所有集合的集合!)小于或等于2^b。但是我的猜测是,你可以有任意的字符串,所以这是不可能的。即使这是可能的,您也必须想出一种映射到哈希空间的方法,这可能是一种挑战

但是,使用好的散列函数,更改集合不太可能最终生成相同的散列值。因此,您可以使用散列来确定不平等性,但是如果散列相同,您仍然需要检查是否相等。(这与哈希集或哈希映射背后的想法相同,其中元素基于哈希代码映射到bucket,但必须检查是否相等)

与Paul提到的类似但不同:您可以创建一个具有版本号的集合实现,并确保在集合发生变化时始终生成一个新的版本号。然后你可以比较版本号?我不确定您是否关心不可变集,或者可变集是否会更改回您看到的版本(即,它是否应该始终获得相同的版本)


希望这能有所帮助。

如果您需要提高hashCode的性能(因为对于一个大型集合来说,它相当昂贵),您可以缓存它并在运行时进行更新

    class MyHashSet<E> extends LinkedHashSet<E> {
    int hashCode = 0;
    @Override
    public boolean add(E e) {
        if (super.add(e)) {
            hashCode ^= e.hashCode();
            return true;
        }
        return false;
    }

    @Override
    public boolean remove(Object o) {
        if(super.remove(o)) {
            hashCode ^= o.hashCode();
            return true;
        }
        return false;
    }

    @Override
    public void clear() {
        super.clear();
        hashCode = 0;
    }

    @Override
    public int hashCode() {
        return hashCode;
    }
}
类MyHashSet扩展LinkedHashSet{ int hashCode=0; @凌驾 公共布尔加法(E){ 如果(超级添加(e)){ hashCode^=e.hashCode(); 返回true; } 返回false; } @凌驾 公共布尔删除(对象o){ 如果(超级删除(o)){ hashCode^=o.hashCode(); 返回true; } 返回false; } @凌驾 公共空间清除(){ super.clear(); hashCode=0; } @凌驾 公共int hashCode(){ 返回哈希码; } }
这是错误的。集合可以更改,但最终仍然具有相同的哈希代码。其含义是单向的。当它们相等时,hashcode必须相同。但哈希代码相同并不意味着它们相等。@Tom:当然,正如我所写的,哈希冲突的可能性仍然存在。如果在任何情况下都必须避免这种情况,那么散列是错误的方法(我强调了这句话)。@tomit没有错;OP特别要求哈希,因此您必须假设他们知道误报的可能性,并对此感到满意。删除了我的否决票,因为您添加了冲突的可能性:-)。对不起,如果一开始就有,我没有注意到。@tomwh00ps,我没有注意到房间里的大象。所以,我收回我所说的。也许“两个版本的设置”是误导。我喜欢比较两个不同的实例。+1:类似的方法是使用ModificationCount。当ModificationCount与上次检查时不同时,集合已更改。@Mulmoth-集合开始时是否相同?然后,您可以捕获更改并比较这些更改。也许我会的