Java正/负零和哈希表

Java正/负零和哈希表,java,double,hashtable,Java,Double,Hashtable,国家 请注意,在大多数情况下,对于class Double、d1和d2的两个实例,d1.equals(d2)的值为true当且仅当 d1.doubleValue() == d2.doubleValue() 还具有值true。但是,有两个例外: 如果d1和d2都表示Double.NaN,则equals方法返回true,即使Double.NaN==Double.NaN具有值false 如果d1表示+0.0,而d2表示-0.0,反之亦然,则即使+0.0==-0.0的值为真,相等测试的值为假

国家

请注意,在大多数情况下,对于
class Double
d1
d2
的两个实例,
d1.equals(d2)
的值为
true
当且仅当

    d1.doubleValue() == d2.doubleValue()
还具有值
true
。但是,有两个例外:

  • 如果
    d1
    d2
    都表示
    Double.NaN
    ,则
    equals
    方法返回
    true
    ,即使
    Double.NaN==Double.NaN
    具有值
    false
  • 如果
    d1
    表示
    +0.0
    ,而
    d2
    表示
    -0.0
    ,反之亦然,则即使
    +0.0==-0.0
    的值为
    ,相等测试的值为
此定义允许哈希表正常运行

为什么这两个例外是“允许哈希表正常运行”所必需的


等价地:哈希表如何无法使用不同的
Double
定义?

这些异常是必要的,因为
Double
作为键的操作与其在计算中的操作不同。正零和负零的位模式不同,因此对于关键目的,它们不能相等,至少不容易相等。
NaN
的位模式只是一个模式,因此出于键的目的,它不能不与自身相等。

这些例外是必要的,因为作为键的
双精度
的操作与其在计算中的操作不同。正零和负零的位模式不同,因此对于关键目的,它们不能相等,至少不容易相等。
NaN
的位模式只是一种模式,因此出于关键目的,它不能不与自身相等。

第一个要点是满足相等和哈希代码的约定所必需的(这是哈希表/哈希映射所使用的)。具体而言,根据以下条件,任何对象都必须等于自身:

equals方法在非null对象引用上实现等价关系:

  • 它是自反的:对于任何非空参考值
    x
    x.equals(x)
    应返回
    true
由于哈希代码具有
equals
方法的行为,因此这也适用于
hashCode

如果根据equals(Object)方法两个对象相等,那么对两个对象中的每一个调用hashCode方法必须产生相同的整数结果

因此,至少相同的
NaN
Double对象必须等于自身。从技术上讲,不要求具有
NaN
值的Double的不同实例必须彼此相等。我的猜测是,他们使所有的
NaN
值相等,因为如果不相等,这会令人困惑,并且与Double基本上是一种值类型这一事实不一致,因此标识相等是不合适的


但是,我想不出为什么第二个例外是允许哈希表正常运行所必需的。

第一个要点是满足等式和哈希代码的约定所必需的(这是哈希表/哈希映射所使用的)。具体而言,根据以下条件,任何对象都必须等于自身:

equals方法在非null对象引用上实现等价关系:

  • 它是自反的:对于任何非空参考值
    x
    x.equals(x)
    应返回
    true
由于哈希代码具有
equals
方法的行为,因此这也适用于
hashCode

如果根据equals(Object)方法两个对象相等,那么对两个对象中的每一个调用hashCode方法必须产生相同的整数结果

因此,至少相同的
NaN
Double对象必须等于自身。从技术上讲,不要求具有
NaN
值的Double的不同实例必须彼此相等。我的猜测是,他们使所有的
NaN
值相等,因为如果不相等,这会令人困惑,并且与Double基本上是一种值类型这一事实不一致,因此标识相等是不合适的

然而,我想不出为什么第二个异常是允许哈希表正常运行所必需的

为什么这两个例外是“允许哈希表正常运行”所必需的

事实上,这种说法有点误导。更准确的说法是,
Double.equals()
定义中的这些异常对于所选的
Double.hashCode()
实现与
equals()
一致是必要的。这个特性确实与Java平台库的哈希实现相关。你会发现,无论是在某地还是在其他地方,都有大量关于这个话题的废话。例如:

由于
hashCode()
/
equals()
一致性的一般主题已经被很好地涵盖,我将重点介绍它们如何应用于类
Double
。这方面有几个细节需要了解:

  • Java
    Double
    Double
    的包装类,
    Double
    是根据IEEE-754二进制双精度格式定义的
  • 在IEEE-754中,正零和负零是不同的值。尽管它们彼此比较相等,但它们具有不同的位模式,并且它们可以通过一些其他属性来区分。这对于某些目的是有用和可取的
  • 另一方面,尽管IEEE-754定义了几种“非数字”(NaN)位模式,Java只使用其中一种
  • IEEE-754规定其特殊NaN值与每个值(包括其本身)进行比较时不相等。这是其中一个