Сравнение двойников в Java дает странные результаты - PullRequest
13 голосов
/ 08 марта 2011

Я действительно не могу понять, почему происходит следующее:

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

Я уверен, что это связано с автобоксомкаким-то образом, но я действительно не знаю, , почему 0 будет по-разному упаковываться, когда используется оператор == и когда .equals называется .

Неэто неявно нарушает equals контракт?

  *  It is reflexive: for any non-null reference value
  *     x, x.equals(x) should return
  *     true.

РЕДАКТИРОВАТЬ :

Спасибо за быстрые ответы.Я подумал, что это по-разному, реальный вопрос: почему это по-другому?Я имею в виду, что это было бы более интуитивно, если d == 0d, чем d.equals(0d), интуитивно и ожидаемо, однако, если d == 0, который выглядит как Integer, равен true, чем 'интуитивно' d.equals(0) также должно быть верным.1030 *

Ответы [ 5 ]

18 голосов
/ 08 марта 2011

просто измените его на

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

Вы сравнивали double с Integer 0

Под крышкой

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

0 будет автоматически помещен в Integer, а экземпляр Integer будет передан в метод equals() класса Double, где он будет сравниваться как

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

который собирается вернуть false конечно.

Update

когда вы проводите сравнение, используя ==, он сравнивает значения, поэтому нет необходимости в автобоксе, он напрямую воздействует на значение. Где equals() принимает Object, поэтому, если вы попытаетесь вызвать d1.equals(0), 0 не является объектом, поэтому он выполнит автобокс и упакует его в Integer, который является объектом.

6 голосов
/ 08 марта 2011

Number объекты равны числам с одинаковым значением, если они относятся к одному типу. То есть:

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

и подобные комбинации все ложные.

В вашем случае, литерал 0 заключен в объект Integer.

5 голосов
/ 29 июня 2011

Вероятно, стоит отметить, что вы должны сравнивать числа с плавающей точкой следующим образом:

|x - y| < ε, ε very small
2 голосов
/ 08 марта 2011

Когда вы выполняете

d == 0

, это повышается до

d == 0.0

, однако нет никаких правил апскейтинга для автобокса, и даже если были равные (Объект) не дает попаданий, которые выхотите удвоить вместо целого числа.

2 голосов
/ 08 марта 2011

d.equals(0): 0 - это int. Код Double.equals() вернет true только для Double объектов.

...