В Java HashSet реализован на основе HashMap, где элементы хранятся в виде ключей. Внутри HashMap используется массив бакетов (table), размер которого всегда степень двойки, по умолчанию 16.
Какой объем памяти выделяется внутри HashSet для хранения двух элементов, один из которых имеет hashCode 0, а другой — 1000000?
В Java HashSet реализован на основе HashMap, где элементы хранятся в виде ключей. Внутри HashMap используется массив бакетов (table), размер которого всегда степень двойки, по умолчанию 16.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
В Java HashSet реализован на основе HashMap, где элементы хранятся в виде ключей. Внутри HashMap используется массив бакетов (table), размер которого всегда степень двойки, по умолчанию 16.
При добавлении первого элемента HashSet выделит массив из 16 бакетов. Каждый бакет — это либо null, либо связанный список (или дерево, если элементов много).
Для двух элементов с hashCode 0 и 1000000:
- Индекс бакета вычисляется как
hash & (table.length - 1). - Для hashCode 0 индекс будет 0.
- Для hashCode 1000000 (в двоичном виде) индекс будет
1000000 & 15.
1000000 в двоичном виде заканчивается на 0, значит индекс будет 0.
Таким образом, оба элемента попадут в один и тот же бакет (индекс 0), и внутри этого бакета будет связанный список из двух элементов.
Объем памяти:
- Массив бакетов: 16 ссылок (каждая 4 или 8 байт в зависимости от JVM).
- Два объекта Node (внутренние элементы HashMap), каждый содержит ключ, значение (для HashSet — фиктивное значение), ссылку на следующий элемент и hash.
Итого, выделяется массив из 16 элементов и два объекта узлов, связанных в цепочку в одном бакете.
Пример:
HashSet<Integer> set = new HashSet<>();
set.add(0); // hashCode = 0
set.add(1000000); // hashCode = 1000000
Оба элемента будут в бакете с индексом 0, что может привести к ухудшению производительности при поиске.