Как связаны методы equals и hashCode и зачем они нужны в Java
Что проверяют
Знаете ли вы контракт между методами и что бывает при его нарушении. Вопрос почти всегда переходит в «что случится с объектом в HashMap, если переопределить только equals».
Как отвечать
equals отвечает на вопрос «это логически один и тот же объект», hashCode возвращает число, по которому хеш-структуры раскладывают объекты по корзинам.
Контракт:
- равные объекты обязаны иметь одинаковый
hashCode; - одинаковый
hashCodeу неравных объектов допустим, это коллизия; - значения обоих методов не должны меняться, пока не менялись поля, участвующие в сравнении.
Отсюда правило: переопределяете один, переопределяйте оба, по одному и тому же набору полей.
Что ломается при нарушении: HashMap сначала ищет корзину по хешу и только внутри неё сравнивает через equals. Если хеш не переопределён, два равных объекта попадут в разные корзины, и map.get(key) вернёт null для ключа, который вы только что положили.
map.put(new User(1), "value");
map.get(new User(1)); // null, если hashCode не переопределёнГде спотыкаются
Не знают про изменяемые поля: объект положили в HashSet, поменяли поле, участвующее в хеше, и он «потерялся» в контейнере. Поэтому ключи делают неизменяемыми.
Считают, что hashCode обязан быть уникальным. Он обязан быть согласованным, а коллизии нормальны.
Забывают про Objects.equals и Objects.hash и пишут сравнение вручную, забывая проверку на null и на класс.
И не помнят, что записи (record) генерируют оба метода сами по всем компонентам.