【问题标题】:Comparing doubles in Java gives odd results比较 Java 中的双精度数会产生奇怪的结果
【发布时间】:2011-06-29 18:00:56
【问题描述】:

我真的不明白为什么会发生以下情况:

Double d = 0.0;
System.out.println(d == 0); // is true
System.out.println(d.equals(0)); // is false ?!

然而,这按预期工作:

Double d = 0.0;
System.out.println(d == 0.0); // true
System.out.println(d.equals(0.0)); // true

我很肯定这在某种程度上与自动装箱有关,但我真的不知道 为什么在使用 == 运算符和调用 .equals 时,0 的装箱方式会有所不同。

这不是隐含违反equals 合约吗?

* 它是自反的:对于任何非空引用值 * x, x.equals(x) 应该返回 * 真的。

编辑:

感谢您的快速答复。我认为它的装箱方式不同,真正的问题是:为什么装箱方式不同?我的意思是,如果d == 0d 比d.equals(0d) 直观且符合预期,这将更直观,但是如果d == 0 看起来像Integer 是true,而不是“直观地”d.equals(0) 也应该是真的。

【问题讨论】:

    标签: java double equals autoboxing


    【解决方案1】:

    改成

    System.out.println(d.equals(0d)); // is false ?! now true
    

    您将 double 与 Integer 0 进行比较

    在封面下

    System.out.println(d.equals(0)); // is false ?!
    

    0 将被自动装箱为Integer,并且 Integer 的一个实例将被传递给Double 类的equals() 方法,它将在其中进行比较

    @Override
        public boolean equals(Object object) {
            return (object == this)
                    || (object instanceof Double)
                    && (doubleToLongBits(this.value) == doubleToLongBits(((Double) object).value));
        }
    

    当然会返回 false。

    更新

    当您使用== 进行比较时,它会比较值,因此不需要自动装箱,它直接对值进行操作。其中equals() 接受Object,因此如果您尝试调用d1.equals(0),0 不是Object,因此它将执行自动装箱并将其打包为Integer,这是一个Object。

    【讨论】:

    • 还是满足于d == 0? :)
    • @Simeon 从评论中回答了您的问题
    • 当d是一个对象而0是原始值时,它如何比较值? IMO 它要么取消装箱 d (到 int ?或者可能使用 Double.doubleValue() ?)或框 0,我看不出它如何在对象和原语上执行 == 。也许我应该问一个单独的问题,因为这个问题有点纠结......
    • 它将调用d.doubleValue() == 0,请在JLS 5.1.7中阅读更多信息
    • @Simeon:这不是 JVM 特定的,因为它是由 JLS 指定的。 Jigar Joshi,抱歉之前的评论,我很困惑;你说的是拆箱转换,但是你应该提到 (docs.oracle.com/javase/specs/jls/se7/html/… 5.1.8]。
    【解决方案2】:

    Number 对象只有在它们属于相同类型时才等于具有相同值的数字。那就是:

    new Double(0).equals(new Integer(0));
    new BigInteger("0").equals(new BigDecimal("0"));
    

    类似的组合都是假的。

    在您的情况下,文字 0 被装箱到 Integer 对象中。

    【讨论】:

    • 为什么在调用 .equals 时将其装箱为 Integer,而在调用 == 时将其装箱?
    • @Simeon 因为equals() 接受Object ,检查here
    • @Jigar 我确实读过你的答案(我什至赞成),但让我感到困惑的是,当我们进行 == 比较时,0 被装箱到 Double (或者它是什么?!什么是即使发生在 == 比较中,也应该创建一个对象,以便它可以正确比较引用?)当我们执行 .equals 时,它被装箱到 Integer
    【解决方案3】:

    可能值得注意的是,您应该像这样比较浮点数:

    |x - y| < ε, ε very small
    

    【讨论】:

    • 如果正确的值不是0.0,比如0.2323121212,我觉得你的答案比较好。
    【解决方案4】:

    d.equals(0) : 0 是 int。 Double.equals() 代码仅对 Double 对象返回 true。

    【讨论】:

    • 0 是一个int 并且将被自动装箱为一个Integer。
    • @Joachim Sauer 这都是假设的 :)
    • 但显然不被 OP 理解。把这些东西拼出来是个好主意。
    【解决方案5】:

    当你表演时

    d == 0
    

    这是向上的

    d == 0.0
    

    但是,自动装箱没有向上转换规则,即使有 equals(Object) 也不会给出您想要 Double 而不是 Integer 的命中。

    【讨论】:

    • 所以它实际上根本没有装箱==它只是演员,这就是我正在寻找的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 2013-03-15
    • 1970-01-01
    • 1970-01-01
    • 2015-10-04
    相关资源
    最近更新 更多