两个Object实例是否可能具有相同的哈希码?
理论上,对象的哈希码是从其内存地址派生的,因此所有哈希码都应该是唯一的,但是如果在GC期间移动对象会怎样?
答案 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)
如果存在与内存地址一样多的哈希码,那么整个内存将存储哈希本身。 : - )
所以,是的,哈希码有时应该重合。