了解双重自动装箱

Understanding Double autoboxing

考虑以下示例:

public static void main(String[] args) {
    double x1 = 0.0, y1 = -0.0;
    Double a1 = x1, b1 = y1;
    System.out.println(x1 == y1);       //1, true
    System.out.println(a1.equals(b1));  //2, false

    double x2 = 0.0, y2 = 0.0;
    Double a2 = x2, b2 = y2;
    System.out.println(x2 == y2);       //3, true
    System.out.println(a2.equals(b2));  //4, true

    double x3 = 0.0/0.0, y3 = 0.0/0.0;
    Double a3 = x3, b3 = y3;
    System.out.println(x3 != y3);       //5, true
    System.out.println(!a3.equals(b3)); //6, false
}

我试图理解 Double 的自动装箱,但无法理解。为什么 //2 打印 false,而 //4 打印 true//1//3 打印 true。为什么它们以不同的方式自动装箱?

查阅以下 JLS 5.1.7 部分我意识到它没有被指定:

If p is a value of type double, then:

  • If p is not NaN, boxing conversion converts p into a reference r of class and type Double, such that r.doubleValue() evaluates to p

  • Otherwise, boxing conversion converts p into a reference r of class and type Double such that r.isNaN() evaluates to true

那么,//2//4//6 是否会产生未指定的行为,并且可能会根据实施情况得出不同的结果?

除非另有说明,否则所有 JAVA 数字类型都是有符号的

因此,0.0 在二进制中表示为 0000000.......0000000

-0.0 表示为 10000000.......0000000

现在,据我了解,当您使用 equals() 时,比较是从 2 个内存位置逐位完成的,因此在您的情况下会失败。

来自 java.lang.Double 包

Double.equals(Double)实现如下

public boolean equals(Object obj) {
    return (obj instanceof Double)
           && (doubleToLongBits(((Double)obj).value) ==
                  doubleToLongBits(value));
}

Double equals 方法记录在 API documentation. The double == operation is documented in the Java Language Specification.

对于大多数数字对,它们的结果相同,但它们基于不同的约定。

双 == 与 IEEE 754 算法兼容,其中 NaN 不等于任何东西,甚至不等于它本身,但 0.0 和 -0.0 是相等的。

Double 旨在让 equals 方法与其 compareTo 兼容,反映总顺序,并与其 hashCode 兼容,因此哈希表将与 Double 键一起使用。 NaN 被视为等于自身,-0.0 小于而不等于 0.0.

如果您仔细阅读 Double 的 Javadoc,您会注意到负零和正零不等价,至少在使用 equals():

进行比较时是这样的

来自Javadoc

Note that in most cases, for two instances of class Double, d1 and d2, the value of d1.equals(d2) is true if and only if

d1.doubleValue() == d2.doubleValue()

also has the value true. However, there are two exceptions:

If d1 and d2 both represent Double.NaN, then the equals method returns true, even though Double.NaN==Double.NaN has the value false. If d1 represents +0.0 while d2 represents -0.0, or vice versa, the equal test has the value false, even though +0.0==-0.0 has the value true.

...for two instances of class Double, d1 and d2, the value of d1.equals(d2) is true if and only if

d1.doubleValue() == d2.doubleValue() 

also has the value true. However, there are two exceptions:

If d1 and d2 both represent Double.NaN, then the equals method returns true, even though Double.NaN==Double.NaN has the value false.

If d1 represents +0.0 while d2 represents -0.0, or vice versa, the equal test has the value false, even though +0.0==-0.0 has the value true.

This definition allows hash tables to operate properly.

请参考:https://docs.oracle.com/javase/7/docs/api/java/lang/Double.html

Double.equals(Object obj) 的 Javadoc:

Note that in most cases, for two instances of class Double, d1 and d2, the value of d1.equals(d2) is true if and only if

d1.doubleValue() == d2.doubleValue() 

also has the value true. However, there are two exceptions:

  • If d1 and d2 both represent Double.NaN, then the equals method returns true, even though Double.NaN==Double.NaN has the value false.
  • If d1 represents +0.0 while d2 represents -0.0, or vice versa, the equal test has the value false, even though +0.0==-0.0 has the value true.

This definition allows hash tables to operate properly.