Получить доступ

Объект добавили в HashSet, после чего изменили у него поле, участвующее в hashCode. Что теперь вернёт contains для этого же объекта?

MiddleКоллекции
Ещё спрашивают так:
  • Объект положили в HashSet, потом изменили у него поле, участвующее в hashCode. Что произойдёт и почему?
Коротко

Скорее всего false: объект лежит в корзине по старому хешу, а ищут по новому. При этом в итерации он останется — и удалить его через remove уже не получится.

  • Утечка памяти, которую трудно заметить
  • Поля в hashCode ключей и элементов множеств — неизменяемые
  • Лучший ключ — неизменяемый: String, record, value-объект

А ещё Иногда contains вернёт true, если новый хеш попал в ту же корзину — ещё коварнее

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Хеш вычисляется в момент размещения, и коллекция не отслеживает изменения элементов. После мутации объект остаётся физически в множестве — итерация его покажет, — но найти его через contains или удалить через remove уже не получится: они идут не в тот бакет. Получается утечка, которую тяжело заметить. Отсюда правило: ключи карт и элементы множеств должны быть неизменяемыми хотя бы в той части состояния, что участвует в hashCode и equals. Именно поэтому в этой роли удобны String, обёртки примитивов, enum и record с неизменяемыми компонентами.

Что хотят услышать

  • Механизм потери объекта.
  • Последствия и правило неизменяемых ключей.

Частые ошибки

  • Использовать изменяемую сущность с изменяемым бизнес-ключом в качестве ключа карты.
  • Считать, что проблема проявится сразу — обычно она всплывает далеко от места мутации.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓Скорее всего false: поиск пойдёт в бакет по новому хешу, а объект лежит в бакете по старому
  • ✗true — сравнение идёт по ссылке, а она не изменилась
  • ✗true — множество пересчитывает хеши при каждом обращении
  • ✗Будет брошено ConcurrentModificationException

Что спросят дальше

  • Почему record — удобный кандидат в ключи?
  • Как это связано с контрактом hashCode?
  • Почему Set в Java устроен поверх Map?
  • Что произойдёт в той же ситуации с TreeSet?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем