.Net等价于Java的System.identityHashCode()

时间:2018-11-13 03:16:08

标签: java c# .net hash

Java的System.identityHashCode()

  

为给定对象返回与将返回的哈希码相同的哈希码   通过默认方法hashCode(),无论给定对象的   类会覆盖hashCode()。

该哈希码基于对象标识,因此对于同一对象,无论该对象是否在对identityHashCode()的调用之间发生了突变,它的哈希码始终相同。

除此之外,任何两个活动对象(带有某些Java运行时)之间都不会发生哈希冲突:(前者是Oracle在下面给出的源代码中的不准确陈述,如Jai的答案显示出来了,正如another bug report所指出的-这基本上使我原来的问题无效...)

  

[...]垃圾对象很容易回收,地址空间为   重用。 Collisons是地址空间重用的结果。如果原来   对象保持活动状态(未GCed),那么您将不会遇到此问题   问题。

Source

.Net中有RuntimeHelpers.GetHashCode(),它满足第一个条件,但不满足第二个条件:

  

请注意,GetHashCode始终为相同的对象引用返回相同的哈希码。但是,事实并非如此:相等的哈希码并不表示相等的对象引用。特定的哈希码值对于特定的对象引用不是唯一的。不同的对象引用可以生成相同的哈希码。

.Net中是否有类似Java的identityHashCode()

编辑:

有人建议这与Memory address of an object in C#相同,但并非相同,因为此处(仅)不能使用内存地址,因为内存管理会移动对象,因此该地址可能会在{一个对象。

2 个答案:

答案 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(),但也通过单独存储引用来处理潜在的冲突。

请注意有关对象寿命的警告。如果您需要临时对象,他建议您重新实现生成器-现在可以更轻松地访问源了。