Вы, наверное, уже знаете, что оператор Java «==» довольно сложен. Потому что это просто бесполезно в большинстве случаев. В Java вы имеете дело в основном с объектами, и вы не можете использовать оператор «==» для сравнения объектов, вместо этого вы должны использовать метод .equals()
. Что касается объекта «==», сравнивайте ссылки на объекты, а не их фактическое содержимое.
Несмотря на это, можно увидеть такой код, который не только использует «==» для сравнения объектов, но и работает корректно. Некоторые части этого кода, обнаруженные в продакшене, можно считать исключительным примером программистской тупости, иначе говоря, шиткод.
Вот наше тестовое приложение. И вы обязательно заметите, какой у него странный вид.
import static java.lang.System.out; import java.math.BigDecimal; public class Main { public static void main(String[] args) { // Note that our variables are objects Integer a = 1; Integer b = 666;
out.println(a == 1); out.println(b == 666);
out.println(b == new Integer(666)); out.println(a == new Integer(1)); out.println(new Integer(1) == new Integer(1));
out.println(a == Integer.valueOf(1)); out.println(b == Integer.valueOf(666));
out.println(Integer.valueOf(666) == Integer.valueOf(666));
BigDecimal bd = BigDecimal.valueOf(33.0); out.println(bd.equals(new BigDecimal("33.0"))); out.println(bd.equals(new BigDecimal("33.00"))); out.println(bd.equals(new BigDecimal("33"))); out.println(bd.equals(new BigDecimal(33))); } }
Давайте углубимся в результаты построчно.
a == 1; // -> true
b == 666; // -> true
У нас есть объект с одной стороны и примитив с другой. Мы не можем сравнивать напрямую, поэтому Java выполняет распаковку — преобразует объект в примитив. И можно сравнивать примитивы с помощью оператора «==».
b == new Integer(600+60+6); // -> false
a == new Integer(1); // -> false
new Integer(1) == new Integer(1) // -> false
Теперь у нас есть объекты по обе стороны от нашего выражения, и они различны независимо от значений, которые они содержат. Все еще выглядит нормально.
a == Integer.valueOf(1); // -> true
Integer.valueOf(1) == Integer.valueOf(1); // -> true
b == Integer.valueOf(666); // -> false
Integer.valueOf(666) == Integer.valueOf(666) // -> false
Вот где все становится сложно. И что, черт возьми, происходит с методом valueOf? Дело в том, что поведение valueOf похоже на автобоксинг. Это означает, что Integer a = 1;
совпадает с Integer a = Integer.valueOf(1);
.
Но почему некоторые значения автоупаковки сопоставимы через «==», а другие нет. Это связано с кэшированием значений объекта Integer от -128 до 127 (включительно). Таким образом, он всегда будет возвращать один и тот же объект (с одной и той же ссылкой) для кэшированных значений. Значение 666 выходит за пределы диапазона кэширования, поэтому каждый раз будет создаваться новый объект.
Ну так если мы будем сравнивать объекты с equals
, то все должно быть в порядке.
a.equals(1); // -> true
b.equals(666); // -> true
Это верно для большинства случаев, но у нашего паршивого Java API есть одна маленькая ловушка.
BigDecimal bd = BigDecimal.valueOf(33.0);
bd.equals(new BigDecimal("33.0")); // -> true
bd.equals(new BigDecimal("33.00")); // -> false
bd.equals(new BigDecimal("33")); // -> false
bd.equals(new BigDecimal(33)); // -> false
В вашем лице программисты :) Получается, что с точки зрения BigDecimal, если представление «33.0» и «33.00» — это разные значения, потому что они имеют разную точность. Неважно, содержат ли объекты BigDecimal одно и то же значение. Если бы не точность, они не могли бы быть равными.
Итак, как мы должны сравнивать BigDecimals?
bd.compareTo(new BigDecimal("33.00")) == 0; // -> true
bd.compareTo(new BigDecimal("33")) == 0; // -> true
bd.compareTo(new BigDecimal(33)) == 0; // -> true
Вот так это работает, чуваки. Спасибо «умным» дебилам, которые поставили этот ино Java API.
Вещи, которые вы должны помнить:
- Автоматическая распаковка в Java может быть сложной
- Используйте примитивы везде, где только можно
equals
метод является единственным способом для объектов- BigDecimal не является обычным объектом, используйте
a.compareTo(b) == 0
для сравнения таких объектов.
Оригинальный URL статьи: https://mixeddev.info/articles/2020/04/11/java-equality-wtfs.html