Как коллизии хэш-функций влияют на работу массива в контексте хэш-таблицы (например, HashMap) в Java?

«Как коллизии хэш-функций влияют на работу массива в контексте хэш-таблицы (например, HashMap) в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Сам по себе массив (как структура с прямым доступом по индексу) не подвержен коллизиям. Однако, когда массив используется как основа хэш-таблицы (бакетный массив в HashMap), коллизии хэш-кодов ключей становятся критичным фактором, влияющим на производительность.

Принцип работы HashMap:

  1. Внутри HashMap есть массив Node<K,V>[] table (бакеты).
  2. При добавлении пары ключ-значение вычисляется hashCode() ключа.
  3. На основе хэша определяется индекс в массиве: index = (n - 1) & hash, где n — размер массива.

Что происходит при коллизии:

  • Коллизия хэшей: Разные ключи попадают в один и тот же индекс (бакет).
  • Разрешение коллизий: Элементы в одном бакете хранятся как связный список (или красно-чёрное дерево, если список становится длинным).

Пример:

HashMap<String, Integer> map = new HashMap<>();
// Предположим, что "key1" и "key2" дают одинаковый хэш и индекс
map.put("key1", 100); // Элемент помещается в бакет table[i]
map.put("key2", 200); // Коллизия! Элемент добавляется в список внутри того же бакета table[i]

System.out.println(map.get("key1")); // 100
// Для поиска: вычисляется индекс i, затем в списке бакета i
// последовательно сравниваются ключи через equals(), пока не найдётся "key1".

Вывод: Массив в HashMap работает корректно при любых коллизиях благодаря механизму цепочек (списков/деревьев). Однако частые коллизии ухудшают производительность, увеличивая длину цепочек.