为了账号安全,请及时绑定邮箱和手机立即绑定

为什么两个具有相同值的原始双精度具有两个不同的标识哈希代码?

为什么两个具有相同值的原始双精度具有两个不同的标识哈希代码?

幕布斯7119047 2022-09-22 16:11:03

我了解到所有具有相同值的原语都具有相同的,因此,当我尝试使用具有相同值的2个双精度值时,我想获得一些 primitives.so,它给出的不同,我做了以下操作:identityHashCodeidentityHashCodeidentityHashCode


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

具有相同值的两个整数具有相同的,但具有相同值的两个双精度值具有不同,为什么会这样?identityHashCodeidentityHashCode


查看完整描述

4 回答

?
慕盖茨4494581

TA贡献1531条经验 获得超11个赞

您的代码正在对基元值进行装箱。(基元值本身没有标识哈希代码,因为这只是一个与对象相关的概念。您的代码等效于以下内容:


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 == yIntegerboxedDouble1 == boxedDouble2identityHashCode


框内整数引用引用同一对象的原因是缓存特定范围内的框内整数类型:


如果装箱值 p 是计算布尔型、char、短整型、整数型或长整型常量表达式 (§15.28) 的结果,并且结果为 true、false、“\u0000”到“\u007f”(包括)范围内的字符,或介于 -128 到 127(包括 128 和 127)范围内的整数,则设 a 和 b 是 p 的任意两次装箱转换的结果。总是 a == b 的情况。


在实践中,范围实际上可以更大,并且实现也可以缓存盒装双精度值,但我还没有看到这种情况发生。


查看完整回答
反对 回复 2022-09-22
?
料青山看我应如是

TA贡献1446条经验 获得超6个赞

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

返回给定对象的哈希代码,与默认方法 hashCode() 返回的哈希代码相同

但当然与 .doubleDouble


查看完整回答
反对 回复 2022-09-22
?
BIG阳

TA贡献1532条经验 获得超1个赞

我了解到所有具有相同值的基元都具有相同的标识哈希代码。

那里至少有两个误解。首先,基元根本没有哈希代码或身份哈希代码。对象可以做到这一点,例如通过自动装箱基元值获得的包装器对象。

其次,正如你自己的实验所证明的那样,整体想法是完全错误的。如果提供基元作为参数,则它将自动装入相应包装类的实例中,并返回结果对象的标识哈希代码。对象的标识哈希代码在其生存期内具有该对象的唯一特征,并且与其状态无关。没有两个同时存在的对象具有相同的标识哈希代码。因此,更有趣的是,您获得的不是自动装箱 s 的不同身份哈希代码,而是自动装箱小整数的相同身份哈希码。System.identityHashCode()double

实际上,这表明 Java 为小整数值维护了一个对象缓存。它在对所涵盖的范围内的值进行自动装箱处理时,以及在处理对这些值的显式调用时使用这些值。因此,在您的示例中,每次自动装入整数 5 时,您都会获得相同的对象,并且您会看到相同的标识哈希代码。如果您使用了足够大的值,则不会看到相同的效果。IntegerInteger.valueOf()

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

另一方面,也许你只是误解了这个教训。表示相同基元类型和值的不同包装对象不具有相同的标识哈希代码,但它们确实具有相同的(常规)哈希代码,因为对于包装类,这是由它们表示的原始值确定的。因此,将代码的结果与以下结果进行比较:

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


查看完整回答
反对 回复 2022-09-22
?
心有法竹

TA贡献1551条经验 获得超5个赞

我了解到所有具有相同值的原语都具有相同的标识哈希代码

这不可能是真的,因为根据定义,原语不是对象,因此首先没有标识哈希代码。

调用 时,参数被框起来为整数或双精度值。System.identityHashCode()

整数装箱对常用整数(默认情况下从 -128 到 127)使用缓存。双拳击的情况并非如此。

尝试使用大int,您也会得到不同的结果。


查看完整回答
反对 回复 2022-09-22

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信