В чем разница между оператором == и методом equals при сравнении объектов в Java
Что проверяют
Знаете ли вы про сравнение ссылок и помните ли ловушку с кэшем Integer.
Как отвечать
Для объектов == сравнивает ссылки: указывают ли обе переменные на один и тот же объект в памяти. Для примитивов он сравнивает значения.
equals это метод, сравнивающий содержимое, если он переопределён. В классе Object реализация по умолчанию делает то же самое, что ==, поэтому у класса без переопределения разницы нет вовсе.
Классические ловушки:
Строки. Литералы попадают в пул и переиспользуются, поэтому "a" == "a" даёт true. Но new String("a") == "a" даёт false, и результат конкатенации во время выполнения тоже не совпадёт по ссылке. Сравнивать строки через == нельзя никогда.
Integer. Кэшируются значения от -128 до 127:
Integer a = 127, b = 127;
a == b; // true
Integer c = 128, d = 128;
c == d; // falseКод работает на тестовых данных и ломается на боевых. Отсюда правило: обёртки сравнивать только через equals, а лучше не смешивать их с примитивами в сравнениях вообще.
Контракт equals, который надо соблюдать при переопределении: рефлексивность, симметричность, транзитивность, согласованность при повторных вызовах, и x.equals(null) всегда false. Вместе с ним обязательно переопределяется hashCode: равные объекты должны иметь равный хеш, иначе объект потеряется в HashMap и HashSet.
Полезные дополнения: Objects.equals(a, b) безопасен при null, а record генерирует equals и hashCode по компонентам автоматически.
Где спотыкаются
Сравнивают строки через ==.
Переопределяют equals и забывают hashCode.
Не знают про кэш Integer и ловят плавающий дефект.
Нарушают симметричность, сравнивая объект с наследником.