У вас есть HashMap
с 16 ведрами. Поскольку это карта Ха sh, вы начинаете с получения hashCode()
ключа, который возвращает значение int
.
Как назначить полный диапазон int
значений до 16 ведер? Одним из способов является использование оператора остатка %
.
Однако деление происходит (относительно) медленно, поэтому реализация HashMap гарантирует, что число сегментов всегда равно показателю 2 (16, 32, 64). , 128, ...), поэтому вместо него можно использовать битовую маскировку. Чтобы замаскировать, вы используете побитовый оператор &
(AND) с buckets - 1
.
Итак, используя ваш hmap
(фактически, LinkedHashMap
для сохранения порядка), вы можете увидеть расчет корзины здесь:
System.out.println("Key Hash Code Bucket");
System.out.println("======= ========== ======");
for (String key : hmap.keySet())
System.out.printf("%-7s %10d & 15 = %d%n", '"' + key + '"', key.hashCode(), key.hashCode() & 15);
Вывод
Key Hash Code Bucket
======= ========== ======
"One" 79430 & 15 = 6
"Two" 84524 & 15 = 12
"Three" 80786814 & 15 = 14
"Four" 2195782 & 15 = 6
"Five" 2190034 & 15 = 2
"Six" 83138 & 15 = 2
"Seven" 79777773 & 15 = 13
"Eight" 66953327 & 15 = 15
"Nine" 2428114 & 15 = 2
"Ten" 83965 & 15 = 13
Здесь, в сегментах 2, 6 и 13, имеется достаточное количество коллизий.
Показанные здесь сегменты не соответствуют тому, что вы видите в отладчике, потому что HashMap
применяет некоторые дополнительные приемы, чтобы попытаться создать лучший дистрибутив, но это необходимая логика c.
Если размер HashMap изменен до 32 сегментов (следующий показатель равен 2), в результате вы получите:
Key Hash Code Bucket
======= ========== ======
"One" 79430 & 31 = 6
"Two" 84524 & 31 = 12
"Three" 80786814 & 31 = 30
"Four" 2195782 & 31 = 6
"Five" 2190034 & 31 = 18
"Six" 83138 & 31 = 2
"Seven" 79777773 & 31 = 13
"Eight" 66953327 & 31 = 15
"Nine" 2428114 & 31 = 18
"Ten" 83965 & 31 = 29
Как видите, ключи перемещены в другие сегменты, и здесь меньше столкновений, в ведрах 6 и 18.