哈希码唯一性

时间:2009-09-04 19:17:56

标签: java

两个Object实例是否可能具有相同的哈希码?

理论上,对象的哈希码是从其内存地址派生的,因此所有哈希码都应该是唯一的,但是如果在GC期间移动对象会怎样?

7 个答案:

答案 0 :(得分:11)

我认为docs for object's hashCode method说明了答案。

  

“尽可能合理,   class定义的hashCode方法   对象确实返回不同的整数   对于不同的对象。 (这是   通常通过转换实现   对象的内部地址   变成一个整数,但是这个   实施技术不是   JavaTM编程所要求的   语言)。“

答案 1 :(得分:11)

给定合理的对象集合,很可能有两个具有相同哈希码的对象。在最好的情况下,它成为生日问题,与数以万计的对象发生冲突。在实践中,使用相对较小的可能哈希码池创建对象,并且只有数千个对象很容易发生冲突。

使用内存地址只是获取稍微随机数的一种方法。 Sun JDK源具有一个开关,可以使用安全随机数生成器或常量。我相信IBM(曾经?)使用快速随机数生成器,但它根本不安全。记忆地址文档中的提及似乎具有历史性(大约十年前,具有固定位置的对象句柄并不罕见)。

这是我几年前为了证明冲突而编写的一些代码:

class HashClash {
    public static void main(String[] args) {
        final Object obj = new Object();
        final int target = obj.hashCode();
        Object clash;
        long ct = 0;
        do {
            clash = new Object();
            ++ct;
        } while (clash.hashCode() != target && ct<10L*1000*1000*1000L);
        if (clash.hashCode() == target) {
            System.out.println(ct+": "+obj+" - "+clash);
        } else {
            System.out.println("No clashes found");
        }
    }
}

RFE澄清文档,因为这种情况过于频繁:CR 6321873

答案 2 :(得分:7)

想一想。有无数个潜在对象,只有40亿个哈希码。显然,无限的潜在对象共享每个哈希码。

Sun JVM要么将Object哈希码基于对象的稳定句柄,要么缓存初始哈希码。 GC期间的压缩不会改变hashCode()。如果有的话,一切都会破裂。

答案 3 :(得分:5)

有可能吗?

是否以合理的频率发生?

没有

答案 4 :(得分:1)

我假设原始问题仅与默认Object实现生成的哈希码有关。事实是,不能依赖哈希码进行相等性测试,并且仅在某些特定的哈希映射操作(例如由非常有用的HashMap实现实现的操作)中使用。

因此他们不需要真正独特 - 他们只需要足够独特,不会产生很多冲突(这将导致HashMap实现效率低下)。

此外,当开发人员实现要存储在HashMaps中的类时,他们将实现一个哈希码算法,该算法对同一类的对象具有较低的冲突机会(假设您只存储同一类的对象)在应用程序HashMaps中,了解数据可以更容易地实现健壮的散列。

另见Ken关于平等的答案,需要相同的哈希码。

答案 5 :(得分:0)

您是在谈论实际的课程Object还是一般的对象?你在问题中同时使用两者。 (现实世界的应用程序通常不会创建很多Object

的实例

对于一般的对象,通常编写一个要覆盖equals()的类;如果你这样做,你还必须覆盖hashCode(),以便该类的两个不同的“相等”实例也必须具有相同的哈希码。在这种情况下,您可能会在同一个类的实例中获得“重复”哈希代码。

此外,在不同的类中实现hashCode()时,它们通常基于对象中的某些内容,因此您最终会使用较少的“随机”值,从而导致不同类的实例之间出现“重复”哈希代码(这些对象是否“相等”。)

在任何真实应用中,找到具有相同哈希码的不同对象并不罕见。

答案 6 :(得分:-2)

如果存在与内存地址一样多的哈希码,那么整个内存将存储哈希本身。 : - )

所以,是的,哈希码有时应该重合。