Вопрос с собеседования · Java

Какое правило связывает equals() и hashCode()?

MiddleРавенство, equals и hashCode
Ещё спрашивают так:
  • Почему при переопределении equals обязательно переопределять и hashCode?
  • Почему в Java при переопределении equals обязательно переопределять и hashCode?
Коротко

Равные по equals объекты обязаны иметь равный hashCode; обратное не требуется — коллизии нормальны. Иначе HashMap и HashSet ищут в другой корзине и не находят равный объект: до вызова equals дело не доходит.

  • Переопределили equals без hashCode — дубликаты в HashSet, «пропавшие» ключи
  • Считать hashCode по тем же полям, что equals: Objects.hash
  • Изменяемые поля в hashCode ключа — объект потеряется после изменения

А ещё Record и Lombok @EqualsAndHashCode генерируют согласованную пару

Попробуйте сами

HashMap: put, коллизия и resize

Подробно

Как HashMap ищет ключ: вычисляет hashCode, по нему выбирает корзину, и только внутри неё сравнивает кандидатов через equals.

class Point {
    final int x, y;
    @Override public boolean equals(Object o) {
        return o instanceof Point p && x == p.x && y == p.y;
    }
    // hashCode не переопределён
}
Set<Point> set = new HashSet<>();
set.add(new Point(1, 2));
set.contains(new Point(1, 2));   // скорее всего false

hashCode по умолчанию — от идентичности объекта, у двух равных точек разные хеши → разные корзины → equals не вызывается.

Контракт hashCode:

  • равные по equals — равные hashCode (обязательно);
  • неравные могут совпадать (коллизия), но чем реже — тем быстрее таблица;
  • значение стабильно, пока не меняются поля, участвующие в equals.

Правильно: Objects.hash(x, y) или вручную 31 * x + y; те же поля, что в equals.

Что хотят услышать

  • Контракт в обе стороны.
  • Механика поиска в HashMap и последствия нарушения.
  • Как реализовать.

Частые ошибки

  • Переопределить equals и забыть hashCode.
  • Делать hashCode на основе изменяемого состояния ключа.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✗Равный hashCode гарантирует равенство по equals
  • ✗hashCode обязан быть уникален у каждого объекта
  • ✗Объекты с разным hashCode могут быть равны по equals, если совпадают поля
  • ✓Равные по equals объекты обязаны иметь равный hashCode

Что спросят дальше

  • Как HashMap обрабатывает коллизии?
  • Почему ключи HashMap лучше делать неизменяемыми?
  • Что будет, если hashCode всегда возвращает 0?
  • Как HashMap обрабатывает коллизии и при чём тут treeify?

Разбор темы

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования