HashMap
содержит определенное количество ведер. Он используется, hashCode
чтобы определить, в какую корзину их поместить. Для простоты представьте его как модуль.
Если наш хэш-код - 123456 и у нас 4 сегмента, 123456 % 4 = 0
значит, элемент попадает в первую корзину, Bucket 1.
Если наша функция хэш-кода хороша, она должна обеспечивать равномерное распределение, поэтому все сегменты будут использоваться примерно одинаково. В этом случае корзина использует связанный список для хранения значений.
Но нельзя полагаться на людей в реализации хороших хэш-функций. Люди часто пишут плохие хеш-функции, что приводит к неравномерному распределению. Также возможно, что нам просто не повезло с нашими вводами.
Чем менее равномерно это распределение, тем дальше мы продвигаемся от операций O (1) и тем ближе мы приближаемся к операциям O (n).
Реализация Hashmap пытается смягчить это, организовывая некоторые сегменты в деревья, а не в связанные списки, если сегменты становятся слишком большими. Это то TREEIFY_THRESHOLD = 8
, для чего. Если ведро содержит более восьми предметов, оно должно стать деревом.
Это дерево - красно-черное дерево. Сначала он сортируется по хеш-коду. Если хэш-коды совпадают, он использует compareTo
метод, Comparable
если объекты реализуют этот интерфейс, иначе хэш-код идентификации.
Если записи удаляются с карты, количество записей в корзине может уменьшиться, так что эта древовидная структура больше не нужна. Вот для чего UNTREEIFY_THRESHOLD = 6
это нужно. Если количество элементов в корзине становится меньше шести, мы можем вернуться к использованию связанного списка.
Наконец, есть файл MIN_TREEIFY_CAPACITY = 64
.
Когда хэш-карта увеличивается в размере, она автоматически меняет размер, чтобы иметь больше сегментов. Если у нас есть небольшая хеш-карта, вероятность того, что мы получим очень полные корзины, довольно высока, потому что у нас не так много разных корзин, в которые можно было бы поместить материал. Намного лучше иметь большую хэш-карту с большим количеством менее заполненных корзин. Эта константа в основном говорит, что нельзя начинать превращать ведра в деревья, если наша хэш-карта очень маленькая - вместо этого следует изменить размер, чтобы стать больше.
Чтобы ответить на ваш вопрос о приросте производительности, эти оптимизации были добавлены для улучшения худшего случая. Я только предполагаю, но вы, вероятно, увидите заметное улучшение производительности из-за этих оптимизаций, только если бы ваша hashCode
функция была не очень хорошей.
String
, имеют гораздо большее пространство значений, чемint
хэш-код, поэтому столкновения неизбежны. Теперь это зависит от фактических значений, таких как фактическиеString
s, которые вы вводите в карту, получаете ли вы равномерное распределение или нет. Плохое распределение может быть результатом просто неудачи.