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