通过哈希比较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。。。; 映射其他=新。。。; 我不需要确保所有元素都相等, 对我来说,相信一个杂烩就足够了 我准备在每一

我想通过一个简单的散列来比较两个Java
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
确实以equal
exampleClase
s给出equal
hashCode()
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之和),也可以这样实现。