Могут ли в HashMap (или HashSet) элементы с разными ключами оказаться в одном бакете?

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

Ответ

Да, это называется коллизией хэша.

Бакет определяется индексом в массиве, который вычисляется как hash(key) % capacity. Разные ключи могут дать одинаковый индекс по двум причинам:

  1. Разные хэш-коды, но одинаковый индекс после модуля.
  2. Одинаковые хэш-коды (прямая коллизия).

Пример коллизии:

HashMap<String, Integer> map = new HashMap<>(4); // Исходная емкость 4
// Предположим, hash("key1") = 5, hash("key2") = 9
// Индекс = hash % 4
map.put("key1", 1); // Индекс: 5 % 4 = 1
map.put("key2", 2); // Индекс: 9 % 4 = 1 -> Коллизия! Оба в бакете 1.

Как Java разрешает коллизии? Внутри бакета элементы хранятся в структуре:

  • До Java 8: связный список.
  • Начиная с Java 8: при достижении определенного порога элементов в бакете список преобразуется в сбалансированное дерево (TreeNode). Это предотвращает деградацию производительности до O(n) при атаках с использованием коллизий.

Таким образом, один бакет может содержать множество пар ключ-значение с разными ключами.