Подтвердить что ты не робот

Java: разные двойные и двойные в сравнении

Я знаю, что Double является классом-оболочкой, и он обертывает номер Double. Сегодня я видел еще одно главное отличие:

double a = 1.0;
double b = 1.0;
Double c = 1.0;
Double d = 1.0;
System.out.println(a == b);  // true
System.out.println(c == d);  // false

Так странно со мной!!!

Итак, если мы используем Double, каждый раз мы должны сделать что-то вроде этого:

private static final double delta = 0.0001;
System.out.println(Math.abs(c-d) < delta); 

Я не могу объяснить, почему Double делают прямое сравнение неправильным. Пожалуйста, объясните мне.

Спасибо:)

4b9b3361

Ответ 1

c и d являются технически двумя разными объектами, а оператор == сравнивает только ссылки.

c.equals(d)

лучше, поскольку он сравнивает значения, а не ссылки. Но все же не идеальный. Сравнение значений с плавающей запятой непосредственно должно учитывать некоторую ошибку (epsilon) (Math.abs(c - d) < epsilon).

Обратите внимание, что:

Integer c = 1;
Integer d = 1;

здесь сравнение даст true, но это более сложное (Integerвнутреннее кэширование, описанное в JavaDoc Integer.valueOf())

Этот метод всегда будет кэшировать значения в диапазоне от -128 до 127 включительно и может кэшировать другие значения за пределами этого диапазона.

Почему valueOf()? Поскольку этот метод неявно используется для реализации автобоксинга:

Integer c = Integer.valueOf(1);
Integer d = Integer.valueOf(1);

См. также

Ответ 2

При применении к выражениям типа класса == всегда будет выполнять сравнительное сравнение (JLS раздел 15.21.3). Итак, эта строка:

System.out.println(c == d); 

проверяет, относятся ли теги c и d к тем же объектам. Авто-бокс в Java всегда (я считаю) создает новый объект для float и double (ситуация сложнее для целых типов 1). Поэтому c и d относятся к разным объектам, поэтому он печатает false.

Если вы хотите сравнить объекты для равенства, вам нужно явно вызвать equals:

System.out.println(c.equals(d));

С double вместо этого используется числовое равенство - как указано в разделе 15.21.1. Отсюда разница в поведении.


1 Для интегрального автобоксинга "маленькие" значения кэшируются - поэтому autoboxing 5 (скажем) будет возвращать одну и ту же ссылку каждый раз. Определение "маленький" является специфичным для реализации, но оно гарантировано в диапазоне от -128 до 127. См. Нижнюю часть раздел 5.1.7 для подробности.

Ответ 3

Используйте equals() для проверки равенства двух объектов. == проверяет, ссылаются ли 2 ссылки на один и тот же объект в памяти.

Ответ 4

Проверка содержимого является надежной только при == при проверке примитивных типов. Для типов объектов всегда лучше использовать метод equals:

c.equals(d)