Что произойдет, если ключ в мапе изменится после помещения и как это влияет на поиск значения
Что проверяют
Знаете ли вы контракт hashCode и equals и понимаете ли, что HashMap раскладывает записи по корзинам один раз, в момент вставки. Проверяют не зубрёжку, а способность объяснить дефект, где значение «пропало» из мапы, хотя его никто не удалял.
Как отвечать
Разберите механику. При put считается хеш ключа, по нему выбирается корзина, туда кладётся узел, и посчитанный хеш сохраняется прямо в узле. Если после этого изменить поле ключа, которое участвует в hashCode, запись останется лежать в старой корзине, а get посчитает новый хеш и пойдёт искать в другую. Результат: null.
Дальше уточнения, которых обычно ждут:
- запись не исчезла:
sizeпрежний, обходentrySetеё показывает,containsValueнаходит значение; - удалить её вызовом
removeс этим же ключом тоже не выйдёт, она останется в мапе навсегда; - иногда значение всё-таки находится: если новый хеш попал в ту же корзину, сравнение идёт через
equals, и оно проходит; - если
hashCodeне переопределён, работает хеш по ссылке, и мутация полей ничего не ломает.
Практический вывод: ключ должен быть неизменяемым (String, Integer, enum, запись с неизменяемыми полями) либо считать hashCode и equals только по той части состояния, которая не меняется, например по идентификатору. Если менять всё-таки нужно, порядок такой: remove, изменение, put обратно. HashSet устроен поверх HashMap, там всё так же. В TreeMap беда другая: порядок задаёт compareTo, изменение поля ломает инвариант дерева, и поиск сворачивает не в ту ветку.
Где спотыкаются
Отвечают одним словом «null», а на уточнение, осталась ли запись в мапе, говорят, что она пропала. Разница важна: это утечка, а не удаление, и в долгой мапе такие записи копятся.
Второе: считают, что хеш пересчитывается при каждом обращении и мапа сама себя починит. Хеш сохранён в узле при вставке и переиспользуется даже при расширении таблицы, поэтому запись так и остаётся в корзине, выбранной по старому значению.
Третье: берут в ключи изменяемую сущность с сеттерами или список, забывая, что мапа хранит ссылку, а не копию. Состояние правит чужой код в другом слое, и поиск ломается далеко от места изменения.