Что нужно учитывать при переопределении метода equals() в Java?

«Что нужно учитывать при переопределении метода equals() в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

При переопределении equals() необходимо соблюдать его контракт, определенный в спецификации Java:

  1. Рефлексивность: x.equals(x) всегда возвращает true.
  2. Симметричность: если x.equals(y) возвращает true, то и y.equals(x) должно возвращать true.
  3. Транзитивность: если x.equals(y) и y.equals(z) возвращают true, то и x.equals(z) должно возвращать true.
  4. Согласованность: повторные вызовы x.equals(y) должны consistently возвращать одно и то же значение, при условии, что информация, используемая в сравнении, не меняется.
  5. Сравнение с null: x.equals(null) всегда должно возвращать false.

Практический пример переопределения:

@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);
}

Критически важное правило: Если вы переопределяете equals(), вы обязаны переопределить hashCode(), чтобы выполнялось условие: если два объекта равны по equals(), то их хэш-коды должны быть одинаковыми. Нарушение этого правила приведет к некорректной работе объектов в HashSet, HashMap и других hash-коллекциях.