Вопрос с собеседования · Java

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

MiddleКоллекции
Ещё спрашивают так:
  • Объект положили в 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?

Разбор темы

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

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования