Ответ
Метод equals(Object obj) определяет логическое равенство объектов по их содержимому, в отличие от оператора ==, который проверяет равенство ссылок (указывают ли две переменные на один и тот же объект в памяти).
Контракт метода equals() (обязательные свойства):
- Рефлексивность:
x.equals(x)всегдаtrue. - Симметричность: если
x.equals(y) == true, то иy.equals(x) == true. - Транзитивность: если
x.equals(y)иy.equals(z), тоx.equals(z). - Согласованность: многократные вызовы
x.equals(y)должны стабильно возвращать одно и то же значение, если данные объектов не менялись. - Сравнение с null:
x.equals(null)всегдаfalse.
Правила переопределения:
- Всегда переопределяйте
hashCode(), если переопределяетеequals(). Объекты, которые равны поequals(), должны возвращать одинаковый хэш-код. - Используйте
instanceofили проверку класса для сравнения типов. - Для сравнения полей-примитивов используйте
==, для объектов —Objects.equals()(корректно обрабатываетnull).
Пример корректного переопределения:
public class Person {
private String name;
private int age;
@Override
public boolean equals(Object o) {
// 1. Проверка ссылки
if (this == o) return true;
// 2. Проверка типа и null
if (o == null || getClass() != o.getClass()) return false;
// 3. Приведение типа
Person person = (Person) o;
// 4. Сравнение значимых полей
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
// Генерация хэш-кода на основе тех же полей
return Objects.hash(name, age);
}
}
Использование Objects.equals(): Этот метод безопасен для null и эквивалентен конструкции (a == b) || (a != null && a.equals(b)).
Ответ 18+ 🔞
А, ну это же про этот ваш священный грааль — метод equals, блядь! Ну что, разжую, как для дебила, но с технической точностью, ёпта.
Смотри, есть у тебя два объекта. Ты на них смотришь и думаешь: «О, да это же одно и то же, сука!». А Java-то тупая, она нихуя не понимает. Для неё это два разных куска памяти, два разных адреса. И оператор == тебе так и скажет: «Не, мудила, это разные ссылки, нихуя не равны». А ты ему: «Да посмотри на содержимое, ебанашка! Имя одинаковое, возраст одинаковый!». Вот для этого и нужен equals — чтобы сравнивать не адреса в памяти, а то, что внутри, по смыслу.
Но тут, сука, не всё так просто. Нельзя просто взять и написать equals как попало. Есть там, блядь, целый контракт, правила, которые нарушать — себя не уважать.
Контракт, блядь, или «правила хорошего тона для equals»:
- Рефлексивность. Объект должен быть равен самому себе.
x.equals(x)— всегдаtrue. Если это не так, ты просто конченый идиот. - Симметричность. Если
xравенy, то иyдолжен быть равенx. Не может быть такого, что Вася считает Петю своим братом, а Петя Ваську — хуем с горы. - Транзитивность. Если
xравенy, аyравенz, тоxобязан быть равенz. Логика, блядь, а не матан какой-то. - Согласованность. Сколько раз ни вызывай
equals— результат должен быть один и тот же, если данные не менялись. Не может объект сегодня быть равным, а завтра — нет, это уже шизофрения. - Сравнение с null. Любой объект, даже самый ебаный, при сравнении с
nullдолжен возвращатьfalse.x.equals(null) -> false. Всё.
А теперь, внимание, ебаный насос! Главное правило:
Если переопределил equals — обязательно переопредели и hashCode(), блядь! Иначе все твои коллекции вроде HashMap или HashSet просто сойдут с ума. Они будут искать объекты не там, и ты будешь месяц дебажить эту хуйню. Объекты, которые equals говорит, что равны, обязаны иметь одинаковый хэш-код. Запомни это, как «Отче наш».
Как это делать, не наступая на грабли:
- Сравнивай себя с собой через
==— это быстрая проверка. - Проверяй, не
nullли тебе подсунули и того же ли класса объект.instanceofилиgetClass()— выбирай по ситуации, но обычноgetClass()строже и надёжнее. - Приводи тип, сука, аккуратно.
- Сравнивай поля. Примитивы — через
==. Объекты — черезObjects.equals(). Это гениальная штука, она сама разберётся сnull, не надо городить велосипеды вродеif (a != null && a.equals(b)).
Смотри, как это выглядит в коде, без всякой понтовой лапши:
public class Person {
private String name;
private int age;
@Override
public boolean equals(Object o) {
// 1. Быстрая проверка: а не я ли это?
if (this == o) return true;
// 2. Он null? Или он вообще с другой планеты (другого класса)?
if (o == null || getClass() != o.getClass()) return false;
// 3. Ладно, приводим тип. Теперь o — это точно Person.
Person person = (Person) o;
// 4. И сравниваем всё, что важно. Возраст как число, имя через умный Objects.equals.
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
// Хэш-код на основе ТЕХ ЖЕ полей, что и в equals! Без этого — пиздец.
return Objects.hash(name, age);
}
}
Вот и вся магия, блядь. Objects.equals() — это твой лучший друг. Он делает ровно то, что ты 100 раз писал вручную: (a == b) || (a != null && a.equals(b)). Не изобретай велосипед, используй готовое, и будет тебе счастье.