Какое правило связывает equals() и hashCode()?
- Почему при переопределении equals обязательно переопределять и hashCode?
- Почему в Java при переопределении equals обязательно переопределять и hashCode?
Равные по equals объекты обязаны иметь равный hashCode; обратное не требуется — коллизии нормальны. Иначе HashMap и HashSet ищут в другой корзине и не находят равный объект: до вызова equals дело не доходит.
- Переопределили equals без hashCode — дубликаты в HashSet, «пропавшие» ключи
- Считать hashCode по тем же полям, что equals: Objects.hash
- Изменяемые поля в hashCode ключа — объект потеряется после изменения
А ещё Record и Lombok @EqualsAndHashCode генерируют согласованную пару
Подробно
Как 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?
Разбор темы
- Равенство: ==, equals и hashCode
Идентичность против логического равенства, контракт equals и hashCode, проблема equals с наследованием и корректная реализация.
- HashMap изнутри: бакеты, treeify, resize
Таблица бакетов, перемешивание хеша и индекс, превращение цепочки в дерево, ресайз и load factor, контракт ключа.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.