Ответ
При реализации equals() необходимо соблюдать его контракт и учитывать несколько критических аспектов до сравнения полей:
- Сравнение ссылок (
==): Проверить, не является ли переданный объект той же самой ссылкой. Это оптимизация. - Проверка на
null: Убедиться, что переданный объект неnull. - Проверка типа (
getClass()илиinstanceof): Определить, можно ли сравнивать объекты. Выбор зависит от требований к наследованию.getClass() == o.getClass()гарантирует строгое равенство классов (не работает с наследниками).o instanceof MyClassпозволяет считать равными объекты родительского и дочернего классов (логика должна быть корректной).
Пример корректной реализации для final-класса:
@Override
public final boolean equals(Object o) {
if (this == o) return true; // 1. Проверка ссылки
if (o == null || getClass() != o.getClass()) return false; // 2. & 3. Проверка null и типа
Person person = (Person) o;
// 4. Сравнение значимых полей
return age == person.age && Objects.equals(name, person.name);
}
Контракт equals() требует соблюдения свойств:
- Рефлексивность:
x.equals(x)— всегдаtrue. - Симметричность: Если
x.equals(y) == true, то иy.equals(x) == true. - Транзитивность: Если
x.equals(y)иy.equals(z), тоx.equals(z). - Согласованность: Многократный вывоз должен возвращать одинаковый результат.
- Сравнение с null:
x.equals(null)— всегдаfalse.