基元上的System.identityHashCode()行为

时间:2017-12-06 14:59:52

标签: java kotlin hashcode primitive

jvm imgui中,我正在使用

System.identityHashCode(i++)

,其中

var i = 0

为每个帧生成一个给定对象的常量id(因此为
能够跟踪它)

但是,有一个user case只是告诉我这仅适用于[0, 125]

中的值

尝试调试并找到错误,我结束了测试这段简短的代码片段:

    var i = 0
    val A = Array(256, { System.identityHashCode(i++) })
    i = 0
    val B = Array(256, { System.identityHashCode(i++) })
    repeat(256) {
        if (A[it] != B[it])
            println("[$it] different, A ${A[it]}, B ${B[it]}")
    }

还有:

  • 字节(完全正常,A == B表示所有256个值)
  • 短裤(不是从128开始工作)
  • ints(不在128工作)
  • 渴望(不在128工作)
  • 浮动(根本不工作)
  • 双打(根本不工作)

为什么?

我是否安全,假设这种行为在其他平台上也是一致的?

1 个答案:

答案 0 :(得分:5)

  

但是,一个用户案例只是向我显示这仅对[0,125]

中的值有效

System.identityHashCode(Object)使用Object而不是原语,这意味着您的i++自动加框为Integer(或Long或... )。对象具有相同标识哈希码的唯一时间很可能(但不总是)在它们是同一对象时。碰巧的是,JVM缓存了少量的Integer用于优化目的,这意味着0到127值的标识哈希码是相同的。

当自动装箱发生时,编译器generates a call to Integer.valueOf(int)。如果我们查看`valueOf(...)的代码,我们会看到:

if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);

因此,存在一个低和高缓存范围,您将从中获得在JVM启动时生成的缓存常量对象。有些JVM参数会影响数字缓存的大小。因此127必须在JVM的缓存范围内,而128及以上则不在。

// both of the 100 values gets auto-boxed to the same Integer object
System.identityHashCode(100) == System.identityHashCode(100)

这基本上等同于比较同一对象的哈希码:

Integer i = new Integer(100);
System.identityHashCode(i) == System.identityHashCode(i)

一旦超过初始缓存的Integer值集,并且指定了更大的int,则在自动装箱时将创建新的Integer对象,因此身份哈希码(很可能)不再相等。

// by default, each of these 1000000 values gets auto-boxed to a different object
System.identityHashCode(1000000) != System.identityHashCode(1000000)

这基本上相当于实例化2个不同的整数并期望它们的哈希码相同:

Integer i1 = new Integer(1000000);
Integer i2 = new Integer(1000000);
System.identityHashCode(i1) != System.identityHashCode(i2)

请注意System.identityHashCode(...) 会返回唯一值,因此如果查看不同的对象,它们可能会生成相同的值(尽管不太可能)。