Что означает эквивалентность объектов в Java и как она определяется?

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

Ответ

В Java эквивалентность объектов определяется семантическим равенством, а не ссылочным (==). Основу составляет контракт методов equals() и hashCode():

  1. equals(Object o) — определяет логическое равенство объектов (например, равны ли их значимые поля).
  2. hashCode() — возвращает целочисленное значение, согласованное с методом equals().

Ключевой контракт:

  • Если a.equals(b) возвращает true, то a.hashCode() обязан быть равен b.hashCode().
  • Обратное неверно: равные хеш-коды не гарантируют равенство объектов (возможны коллизии).

Пример корректной реализации:

public class Person {
    private final String id;
    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return id.equals(person.id); // Сравниваем по уникальному идентификатору
    }

    @Override
    public int hashCode() {
        return Objects.hash(id); // Хеш-код вычисляется по тем же полям, что и equals
    }
}

Почему это важно? Нарушение этого контракта приводит к некорректной работе коллекций, основанных на хешах (HashMap, HashSet).