Java的System.identityHashCode()
为给定对象返回与将返回的哈希码相同的哈希码 通过默认方法hashCode(),无论给定对象的 类会覆盖hashCode()。
该哈希码基于对象标识,因此对于同一对象,无论该对象是否在对identityHashCode()
的调用之间发生了突变,它的哈希码始终相同。
除此之外,任何两个活动对象(带有某些Java运行时)之间都不会发生哈希冲突:(前者是Oracle在下面给出的源代码中的不准确陈述,如Jai的答案显示出来了,正如another bug report所指出的-这基本上使我原来的问题无效...)
[...]垃圾对象很容易回收,地址空间为 重用。 Collisons是地址空间重用的结果。如果原来 对象保持活动状态(未GCed),那么您将不会遇到此问题 问题。
.Net中有RuntimeHelpers.GetHashCode()
,它满足第一个条件,但不满足第二个条件:
请注意,GetHashCode始终为相同的对象引用返回相同的哈希码。但是,事实并非如此:相等的哈希码并不表示相等的对象引用。特定的哈希码值对于特定的对象引用不是唯一的。不同的对象引用可以生成相同的哈希码。
.Net中是否有类似Java的identityHashCode()
?
编辑:
有人建议这与Memory address of an object in C#相同,但并非相同,因为此处(仅)不能使用内存地址,因为内存管理会移动对象,因此该地址可能会在{一个对象。
答案 0 :(得分:3)
当前Java的Object#hashCode()
和System#identifyHashCode()
不会不确保返回唯一值。对此已经存在疑问,this是一个示例。
您提到了一个错误报告,该报告指出发生冲突的原因是 ,因为对象被垃圾回收,并且相同的内存地址被重用。但是,修改相同的测试用例将证明相反:
List<Object> allObjs = new ArrayList<>(); // Used to prevent GC
Set<Integer> hashes = new HashSet<Integer>(1024);
int colls = 0;
for (int n = 0; n < 100000; n++)
{
Integer obj = new Integer(88);
allObjs.add(obj); // keep a strong reference to prevent GC
int ihash = System.identityHashCode(obj);
Integer iho = Integer.valueOf(ihash);
if (hashes.contains(iho))
{
System.err.println("System.identityHashCode() collision!");
colls++;
}
else
{
hashes.add(iho);
}
}
System.out.println("created 100000 different objects - "
+ colls
+ " times with the same value for System.identityHashCode()");
System.out.println("Size of all objects is " + allObjs.size());
System.out.println("Size of hashset of hash values is " + hashes.size());
结果:
System.identityHashCode() collision!
System.identityHashCode() collision!
System.identityHashCode() collision!
created 100000 different objects - 3 times with the same value for System.identityHashCode()
Size of all objects is 100000
Size of hashset of hash values is 99997
在链接的SO问题中,还提到在JRE的某些实现中,大大降低了冲突率。但是,似乎没有实现能够阻止 all 冲突。因此,即使在Java中,也无法确保哈希码的唯一性。
因此,不要简单地基于一种来源。评论它的人也只是Oracle团队的成员,而他或她很可能不是设计这个人的人。
在C#和Java中,您都必须创建自己的某种独特的数字生成器。因此,NPras提供的solution似乎适用于.NET。
答案 1 :(得分:2)
我将带您到following answer from Eric Lippert(他是C#语言设计和编译器团队的成员)那里,他建议使用ObjectIDGenerator。
要为对象生成唯一的ID,您可以使用我们方便地为您提供的
ObjectIDGenerator
Looking at the reference source(好吧,他们现在开放了框架的源代码),它确实使用了RuntimeHelpers.GetHashCode()
,但也通过单独存储引用来处理潜在的冲突。
请注意有关对象寿命的警告。如果您需要临时对象,他建议您重新实现生成器-现在可以更轻松地访问源了。