javadocs状态
请注意,在大多数情况下,对于
class Double
,d1
和d2
的两个实例,d1.equals(d2)
的值为true
当且仅当< / p>d1.doubleValue() == d2.doubleValue()
也具有值
true
。但是,有两个例外:
- 如果
d1
和d2
都代表Double.NaN
,则equals
方法会返回true
,即使Double.NaN==Double.NaN
的值为false
1}}。- 如果
d1
代表+0.0
而d2
代表-0.0
,反之亦然,则等值测试的值为false
,即使+0.0==-0.0
}具有值true
。此定义允许哈希表正常运行。
为什么这两个例外必须“允许哈希表正常运行”?
等效地:哈希表如何不能使用Double
的不同定义?
答案 0 :(得分:4)
为什么这两个例外必须允许哈希表正常运行&#34;?
事实上,这种说法有点误导。更准确地说,Double.equals()
的定义中的那些例外对于Double.hashCode()
选择的实现与equals()
一致是必要的。该特性确实与Java平台库的哈希实现相关。你会在SO和其他地方找到大量专门针对该主题的措辞。例如:
由于涵盖了hashCode()
/ equals()
一致性的一般主题,因此我将重点介绍它们如何应用于课程Double
。这个领域有几个细节需要理解:
Double
是double
的包装类,double
是根据IEEE-754二进制双精度格式定义的。Double.hashCode()
是根据包裹double
的位模式的算术运算定义的。因为Double.hashCode()
是根据包裹的double
位模式计算的,并且正零和负零的位模式不同,所以哈希码为Double(+0.0)
和{{ 1}}不同。如果两个此类Double(-0.0)
实例比较相等,那么这会使hashCode()
实现与equals()
不一致。因此,Double
被定义为不比较相等。 这不是唯一的选择 :Double.equals()
可以改为定义,以便零的两种口味具有相同的哈希码。
另一方面,因为Java只提供一个类型为hashCode()
的NaN值,并且具有特定的位模式,所以表示该值的double
个实例产生相同的哈希码。虽然这是从Double
的所选实现中得出的结果,但是在类hashCode()
中镜像IEEE-754等式语义并不容易,因为这样做需要违反比{更重要的不变量Double
。 {1}}与equals()
保持一致:等于反身。也就是说,对于任何非空引用都hashCode()
,a
为真,预计总是如此。
答案 1 :(得分:2)
第一个要点是满足equals和hash代码的合同(这是HashTable / HashMap使用的)。具体而言,根据equals Javadoc:
,任何对象都必须等于自身equals方法在非null对象引用上实现等价关系:
- reflexive :对于任何非空参考值
x
,x.equals(x)
应返回true
。
由于哈希码为required to be consistent且具有equals
方法的行为,因此这也适用于hashCode
。
如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须产生相同的整数结果。
因此,至少相同的NaN
Double对象必须等于它自己。从技术上讲,不需要具有NaN
值的Double的不同实例必须彼此相等。我的猜测是他们使所有NaN
值相等,因为如果不是这样会让人感到困惑,并且与Double基本上是值类型的事实不一致,所以身份相等是不合适的。
但是我想不出为什么第二个例外是允许哈希表正常运行所必需的原因。
答案 2 :(得分:1)
这些例外是必要的,因为Double
作为关键字的操作与其在计算中的操作不同。正负零的位模式不同,因此对于关键目的,它们不能相等,至少不容易。 NaN
的位模式只是一种模式,因此出于关键目的,它不能不等于它自己。