Можно ли переопределить хэш-функцию в Java и как это сделать
Что проверяют
Знаете ли вы контракт hashCode и equals и последствия его нарушения для коллекций. Формально вопрос про синтаксис, фактически про то, понимаете ли вы, почему объект, положенный в HashSet, потом перестаёт находиться.
Как отвечать
Да, hashCode это обычный метод класса Object, и он переопределяется вместе с equals. Контракт простой: равные по equals объекты обязаны возвращать одинаковый hashCode, а разные объекты совпадать по хэшу вправе. Хэш не уникален, он лишь указывает корзину, внутри которой сравнение идёт уже через equals.
На практике метод пишут по тем полям, что участвуют в равенстве:
@Override public int hashCode() {
return Objects.hash(id, name);
}В Kotlin, на котором сейчас пишут почти весь Android, оба метода генерирует data class по свойствам из первичного конструктора, и руками их трогают редко. Стоит добавить, зачем это нужно именно на мобильном проекте: на equals опирается сравнение элементов в DiffUtil, и от него зависит, перерисует список строку целиком или не тронет вовсе.
Отдельно скажите, что в хэш берут только неизменяемые поля. Если объект уже лежит в HashMap и вы поменяли поле, участвующее в хэше, он останется в старой корзине, и поиск по нему вернёт пустоту.
Где спотыкаются
Переопределяют один метод из пары. Свой equals без hashCode ломает все хэш-коллекции разом, и ошибка всплывает далеко от места правки.
Пытаются сделать хэш уникальным и городят формулу подлиннее. Уникальность не требуется и на тридцати двух битах недостижима, а требуются дешевизна вычисления и равномерность распределения.
Используют hashCode как стабильный идентификатор: кладут его в базу или отдают из getItemId адаптера. Значение не гарантировано постоянным между запусками и коллизий не исключает, поэтому идентификатор должен приходить вместе с данными.