通过哈希比较java映射
我想通过一个简单的散列来比较两个Java通过哈希比较java映射,java,collections,hash,comparison,compare,Java,Collections,Hash,Comparison,Compare,我想通过一个简单的散列来比较两个JavaMaps 每个对象位于不同的计算机上,因此通过网络发送散列比发送整个对象进行比较要便宜 例如,我有两个ExampleClass的HashMaps Map<String,ExampleClass> One=new ...; Map<String,ExampleClass> Other=new ...; Map One=new。。。; 映射其他=新。。。; 我不需要确保所有元素都相等, 对我来说,相信一个杂烩就足够了 我准备在每一
Map
s
每个对象位于不同的计算机上,因此通过网络发送散列比发送整个对象进行比较要便宜
例如,我有两个ExampleClass的HashMap
s
Map<String,ExampleClass> One=new ...;
Map<String,ExampleClass> Other=new ...;
Map One=new。。。;
映射其他=新。。。;
我不需要确保所有元素都相等,
对我来说,相信一个杂烩就足够了
我准备在每一边迭代并创建一个“自制散列”,然后将其发送到网络,以最终比较例如int
或其他内容
如果每次在集合中添加或删除一个对象时都计算这个“散列”就好了,这样我就不用迭代整个对象了。我必须封装
映射的每个添加/删除。是否有这样的Java库?如果所有类都实现了hashCode()
(不使用),则可以使用
这里需要注意的是,如果您的ExampleClass
没有实现hashCode()
,那么相同的项可能在两台不同的机器上具有不同的哈希值,这将导致映射的哈希值不同
澄清:
Map
实现了一个hashCode()
,它被定义为它的Map.Enytry
的hashCode()
之和
定义为键的hashCode()
和值的hashCode()
的异或。
您的键是String
s——它们有一个定义良好的hashCode()
(两个相等的字符串总是具有相同的hashCode()
)。
您的值是ExampleClass
实例——它们还需要定义良好的hashCode()
总之,包含{s1->ec1,s2->ec2}
的映射的哈希代码等于:
(s1.hashCode() ^ ec1.hashCode()) + (s2.hashCode() ^ ec2.hashCode())
这意味着它取决于ExampleClass
的hashCode()
如果ExampleClass
确实以equalexampleClase
s给出equalhashCode()
s的方式实现了hashCode()
,那么一切都会正常工作。
如果ExampleClass
没有实现hashCode()
,它将使用Object
的hashCode()
,这几乎总是会给你不同的hashCode()
,一个简单的解决方案就是对映射中每个对象的哈希进行异或运算,或者对其进行简单的派生。因为a^a=0
和a^b^a=b
对于所有的a和b,(xor是可交换的、关联的,并且是它自己的逆),而且由于xor是便宜的,所以您的添加和删除操作只能对添加或删除项的(可能派生的)哈希代码进行xor
您可能希望使用派生的哈希值,以避免映射具有所有相同的键和值,但它们之间的某些映射是转置的。一个简单的派生哈希可能是key.hashCode()-value.hashCode()
,这样可以避免大多数情况
因此,您的代码可能如下所示:
public class MyMap<K, V> extends HashMap<K, V>{
private int hash = 0;
@Override
public int hashCode() {return hash;}
@Override
public V put(K key, V value) {
V old = super.put(key, value);
if (old != null) this.hash ^= key.hashCode() - old.hashCode();
this.hash ^= key.hashCode() - value.hashCode();
return ret;
}
@Override
public V remove(K key) {
V ret = super.remove(key);
if (ret != null) this.hash ^= key.hashCode() - ret.hashCode();
return ret;
}
}
公共类MyMap扩展了HashMap{
私有整数散列=0;
@凌驾
public int hashCode(){return hash;}
@凌驾
公共V输入(K键,V值){
V old=super.put(键,值);
如果(old!=null)this.hash^=key.hashCode()-old.hashCode();
this.hash^=key.hashCode()-value.hashCode();
返回ret;
}
@凌驾
公共V移除(K键){
V ret=超级移除(键);
如果(ret!=null)this.hash^=key.hashCode()-ret.hashCode();
返回ret;
}
}
请注意,一些更高级的方法(例如,从集合中添加多个项)可能安全,也可能不安全,具体取决于实现。您是否在映射对象本身上尝试过Object.hashCode()?您需要如何确定您的答案?这里提到的Object.hashCode如果您需要一个“OK”级别的准确度,可能会很好,但是哈希冲突可能也确实会发生!如果您需要更高级别的检测,您可能会考虑使用加密散列,例如ShA512Error,我认为这是truthistic的一种回答。史提芬“OK”的准确度级别= OK)它是为了保持本地地图用网络地图更新(以预想暂时(但更慢)更新,以防万一哈希失败)。如果您存储在映射中的类实现了hashCode,并且您使用的映射扩展了AbstractMap,那么文档提供了必要的功能。“映射的哈希代码定义为映射的entrySet()视图中每个条目的哈希代码之和。”ptomli和truth..,据我所知,你说我必须实现hashCode(),就像在@stefan answer中一样,但同时,你说我可以“使用”映射的hashCode(),这对我编辑中的细节有点混淆。您不需要为Map
重新实现hashcode——它已经正确实现了hashcode()
。对于要放入映射中的自定义类(您的ExampleClass
),确实需要实现hashCode()
)。(即使你同意stefan的答案,你也需要这样做)当添加多个项目时,可以理解为迭代整个地图,但不是一次添加/删除,尽管我会使用其他哈希,这似乎是重写put/remove方法的好方法。这是一个很好的优化,因为它更新了hashcode,而不是每次调用hashcode()
时都重新计算它。尽管我建议遵循接口文档中给出的hashCode
的定义(XOR之和),也可以这样实现。