Для чего нужен метод equals() в Java и как его правильно переопределять?

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

Ответ

Метод equals(Object obj) определяет логическое равенство объектов по их содержимому, в отличие от оператора ==, который проверяет равенство ссылок (указывают ли две переменные на один и тот же объект в памяти).

Контракт метода equals() (обязательные свойства):

  1. Рефлексивность: x.equals(x) всегда true.
  2. Симметричность: если x.equals(y) == true, то и y.equals(x) == true.
  3. Транзитивность: если x.equals(y) и y.equals(z), то x.equals(z).
  4. Согласованность: многократные вызовы x.equals(y) должны стабильно возвращать одно и то же значение, если данные объектов не менялись.
  5. Сравнение с 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)).