Ответ
Переопределяя equals(), необходимо обеспечить выполнение пяти ключевых свойств (контрактов):
- Рефлексивность (Reflexive): Объект должен быть равен самому себе.
x.equals(x)всегда возвращаетtrue.
- Симметричность (Symmetric): Если
xравенy, то иyдолжен быть равенx.- Если
x.equals(y)возвращаетtrue, тоy.equals(x)также должно возвращатьtrue.
- Если
- Транзитивность (Transitive): Если
xравенy, аyравенz, тоxдолжен быть равенz.- Если
x.equals(y)иy.equals(z)возвращаютtrue, тоx.equals(z)также должно возвращатьtrue.
- Если
- Консистентность (Consistent): Многократные вызовы
equals()для неизмененных объектов должны возвращать одинаковый результат.- Результат не должен зависеть от времени вызова или случайных факторов.
- Сравнение с
null: Любой объект не должен быть равенnull.x.equals(null)всегда возвращаетfalse.
Важное правило: Если переопределяется equals(), обязательно должен быть переопределен и hashCode(), чтобы выполнялся его контракт: равные объекты должны иметь равные хэш-коды.
Пример корректной реализации для класса Person:
@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;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age); // Согласованность с equals
}