equals и hashCode: зачем и как
Вопрос
Зачем переопределять equals и hashCode вместе? Что сломается, если нарушить контракт, и как правильно их писать?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Контракт: равные по equals имеют равный hashCode
Хеш-коллекции ищут корзину по hashCode, затем сравнивают equals
Без hashCode равный объект не находится в HashMap/HashSet
Поля из hashCode не должны меняться, пока объект в коллекции
Использовать одни и те же поля в обоих методах, Objects.hash/Objects.equals
Для значений record генерирует оба метода
Что могут спросить следом
- Что будет, если hashCode всегда возвращает 1?
- instanceof или getClass в equals: что выбрать?
- Как equals работает у JPA-сущностей с генерируемым id?
Разбор
HashMap и HashSet сначала по hashCode выбирают корзину, а внутри неё сравнивают equals. Отсюда контракт: если объекты равны по equals, хеши обязаны совпадать. Если переопределить только equals, два логически равных объекта попадут в разные корзины, и contains вернёт false. Пишу оба метода по одному и тому же набору полей: Objects.equals для полей и Objects.hash для хеша, сигнатура строго equals(Object) с @Override. Поля, участвующие в хеше, не должны меняться, пока объект лежит в коллекции, иначе он потеряется. Если hashCode вернёт константу, всё будет работать, но поиск выродится в линейный. Для классов-значений сейчас просто беру record.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.