Объект добавили в HashSet, после чего изменили у него поле, участвующее в hashCode. Что теперь вернёт contains для этого же объекта?
- Объект положили в HashSet, потом изменили у него поле, участвующее в hashCode. Что произойдёт и почему?
Скорее всего false: объект лежит в корзине по старому хешу, а ищут по новому. При этом в итерации он останется — и удалить его через remove уже не получится.
- Утечка памяти, которую трудно заметить
- Поля в hashCode ключей и элементов множеств — неизменяемые
- Лучший ключ — неизменяемый: String, record, value-объект
А ещё Иногда contains вернёт true, если новый хеш попал в ту же корзину — ещё коварнее
Подробно
Хеш вычисляется в момент размещения, и коллекция не отслеживает изменения элементов. После мутации объект остаётся физически в множестве — итерация его покажет, — но найти его через contains или удалить через remove уже не получится: они идут не в тот бакет. Получается утечка, которую тяжело заметить. Отсюда правило: ключи карт и элементы множеств должны быть неизменяемыми хотя бы в той части состояния, что участвует в hashCode и equals. Именно поэтому в этой роли удобны String, обёртки примитивов, enum и record с неизменяемыми компонентами.
Что хотят услышать
- Механизм потери объекта.
- Последствия и правило неизменяемых ключей.
Частые ошибки
- Использовать изменяемую сущность с изменяемым бизнес-ключом в качестве ключа карты.
- Считать, что проблема проявится сразу — обычно она всплывает далеко от места мутации.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗true — HashSet сравнивает объекты по ссылке, а ссылка не изменилась
- ✗true — множество пересчитывает хеши при каждом обращении
- ✗Будет брошено ConcurrentModificationException
- ✓Скорее всего false: поиск идёт в бакет по новому хешу
Что спросят дальше
- Почему record — удобный кандидат в ключи?
- Как это связано с контрактом hashCode?
- Почему Set в Java устроен поверх Map?
- Что произойдёт в той же ситуации с TreeSet?
Разбор темы
- Set: HashSet, LinkedHashSet, TreeSet
Почему Set построен поверх Map, три реализации и их гарантии порядка, роль equals/hashCode.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.