为什么两个具有相同值的原始双精度数具有两个不同的identityHashCode?

时间:2019-04-05 13:24:36

标签: java double

我了解到所有具有相同值的图元都具有相同的identityHashCode,因此,我希望获得identityHashCode的一些图元。因此,当我尝试使用具有相同值的2个双精度数时,会给出不同的{{1} }我做到了:

identityHashCode

具有相同值的两个整数具有相同的int xInt=5; int yInt=5; System.out.println(System.identityHashCode(xInt));//output:1867083167 System.out.println(System.identityHashCode(yInt));//output:1867083167 double double1=5; double double2=5; System.out.println(System.identityHashCode(double1));//output:1915910607 System.out.println(System.identityHashCode(double2));//output:1284720968 ,但是具有相同值的两个双精度具有不同的identityHashCode,为什么?

4 个答案:

答案 0 :(得分:7)

您的代码将原始值装箱。 (原始值本身没有标识哈希码,因为这只是与对象相关的概念。)您的代码等效于此:

int xInt=5;
int yInt=5;

Integer xInteger = xInt;
Integer yInteger = yInt;

System.out.println(System.identityHashCode(xInteger));
System.out.println(System.identityHashCode(yInteger));

double double1=5;
double double2=5;

Double boxedDouble1 = double1;
Double boxedDouble2 = double2;

System.out.println(System.identityHashCode(boxedDouble1));
System.out.println(System.identityHashCode(boxedDouble2));

现在,如果您比较引用本身,就会发现xInteger == yInteger是正确的,但是boxedDouble1 == boxedDouble2是错误的……所以identityHashCode可以准确地表示这种关系。

装箱的整数引用引用同一对象的原因是boxed integral types within a particular range are cached

  

如果要装箱的值p是对boolean,char,short,int或long类型的常量表达式(第15.28节)求值的结果,并且结果为true,false,则是'\ u0000范围内的字符'到'\ u007f'(含)或-128至127(含)范围内的整数,则令a和b为p的任何两次装箱转换的结果。通常= = b。

实际上,范围可以更大,并且实现可以缓存盒装功能也可以加倍,但是我还没有看到这种情况。

答案 1 :(得分:0)

  

我了解到所有具有相同值的原语都具有相同的identityHashCode

那是不对的,因为根据定义,基元不是对象,因此一开始就没有身份哈希码。

调用System.identityHashCode()时,该参数将以整数或Double形式出现。

并且Integer装箱使用a cache for the frequently used integers(默认为-128到127)。 Double Boxing并非如此。

以较大的整数进行尝试,您也会得到不同的结果。

答案 2 :(得分:0)

这里有一个拳击问题-您无法将原始数据类型与identityHashCode进行比较,因为它使用Object作为其参数。

  

为给定对象返回与将返回的哈希码相同的哈希码   通过默认方法hashCode()

但是,当然doubleDouble不同。

答案 3 :(得分:0)

  

我了解到所有具有相同值的原语都具有相同的identityHashCode。

至少有两个误解。首先,基元根本没有哈希码或身份哈希码 。是对象,例如通过自动装箱原始值获得的包装对象。

第二,正如您自己的实验所证明的那样,总体思路是错误的。如果您提供原语作为System.identityHashCode()的参数,则该原语将自动装箱到适当包装类的实例中,并返回结果对象的标识哈希码。对象的身份哈希码是该对象在其生存期内的唯一特征,并且独立于其状态。不能同时存在两个对象具有相同的身份哈希码。那么,更有趣的是,您没有为自动装箱的double获得不同的身份哈希码,而是为自动装箱的小整数获得了相同身份哈希码。

实际上,这表明Java维护了Integer对象的高速缓存,以存储较小的整数值。当自动装箱覆盖范围内的值时,以及在处理这些值的显式Integer.valueOf()调用时,它将使用它们。因此,在您的示例中,每次对整数5进行自动装箱时,都会得到相同的对象,并且看到相同的标识哈希码。如果您使用足够大的值,那么您将不会看到相同的效果。

Java不会对值为{5.0的Double执行此类缓存。

另一方面,也许您只是误解了这一课。表示相同原始类型和值的不同包装对象没有相同的 identity 哈希码,但 do 却具有相同的(常规)哈希码,因为包装器类由它们表示的原始值确定。因此,将您的代码结果与以下结果进行比较:

    System.out.println(Double.valueOf(double1).hashCode());
    System.out.println(Double.valueOf(double2).hashCode());