Какое поведение будет при переопределении hashCode всех классов в 1
Что проверяют
Знаете ли вы контракт equals/hashCode и как на самом деле устроен HashMap. Хороший ответ разделяет два вопроса: сломается ли логика и что станет со скоростью. Следом часто спрашивают про изменения HashMap в Java 8 и про андроидный ArrayMap.
Как отвечать
Сначала корректность. Контракт требует одного: равные по equals объекты обязаны давать одинаковый хэш. Константа 1 это условие формально выполняет, поэтому HashMap, HashSet, contains() и remove() продолжат работать правильно. Окончательное решение, тот ли это ключ, всегда принимает equals, хэш лишь сужает поиск.
Потом производительность:
- одна корзина: все ключи падают в один бакет, вместо почти константного доступа получается поиск по цепочке, O(n) на операцию и до O(n²) на заполнение;
- treeification: с Java 8 длинная цепочка превращается в красно-чёрное дерево, когда в ней 8 элементов, а таблица не меньше 64 бакетов. На Android с версии 7 это тот же
HashMapиз OpenJDK; - дерево не всегда спасает: при равных хэшах узлы упорядочиваются через
compareTo. Если ключи реализуютComparable, поиск становится O(log n), если нет, дерево приходится обходить целиком; - ресайз бесполезен: таблица всё равно растёт по коэффициенту загрузки 0.75, но расширение не разводит ключи по разным бакетам;
ArrayMap: хранит отсортированный массив хэшей и ищет бинарным поиском, а при одинаковых хэшах переходит к линейному перебору.
Итог: всё работает правильно, но медленно.
Где спотыкаются
Утверждают, что «уникальность нарушится» и HashSet начнёт хранить дубли. Нет, дубли отсекает equals, хэш на это не влияет.
Путают направление контракта: одинаковый хэш у разных объектов допустим, недопустим разный хэш у равных объектов. Поэтому опасен переопределённый equals без hashCode: равные объекты попадают в разные бакеты и не находятся. Константный хэш из вопроса бьёт только по скорости.
Говорят «будет медленнее» без масштаба. Покажите последствия: на тысяче ключей каждая операция превращается в сотни вызовов equals, и если это происходит в onBindViewHolder или внутри композиции, вы видите пропущенные кадры.