我明白,当我们声明如下地图时:
Map <String, Integer> map = new HashMap ();
默认加载因子为0.75,其大小为16,当地图的桶超过12个元素的数量时,大小将变为32。
然而,当使用put函数时,map选择将放置对象的桶的索引的方式是由hascode%n
定义的,但是当map大小超过加载因子时会发生什么?n不再具有相同的值,因此,如果在应用hascode%n
时,结果索引将与以前不同,您如何找到先前设置的条目?
我的最后一个问题是:
我们增加大小后,桶的索引怎么会一样?
简单的答案是它不能。HashMap
必须在扩展时对所有元素执行重新散列。
请参阅以下方法:
/**
* Transfers all entries from current table to newTable.
*/
void transfer(Entry[] newTable, boolean rehash) {
由resize
调用。其中的JavaDoc说
将此映射的内容重新散列为具有更大容量的新数组。当此映射中的键数达到其阈值时,会自动调用此方法。
强调我的
另见:
HashMap
的默认初始容量为16,负载因子为0.75f(即当前地图大小的75%)。负载因子表示HashMap
容量应该翻倍的级别。
例如容量和负载因子的乘积为16*0.75=12
。这表示将第12个键值对存储到HashMap
后,其容量变为32。
供进一步曝光
进一步的过程解释
哈希映射的重新散列是在映射中的元素数量达到最大阈值时完成的。
通常负载因子值为0.75,默认初始容量值为16。一旦元素数量达到或超过容量的0.75倍,就会发生map的rehash。在这种情况下,当元素数量为12时,就会发生rehash。(0.75*16=12)
当重新散列发生时,可以使用新的散列函数,甚至可以使用相同的散列函数,但是值所在的桶可能会发生变化。基本上,当重新散列发生时,桶的数量大约增加了一倍,因此必须放置值的新索引会发生变化。
重新散列时,每个桶的链表顺序颠倒。发生这种情况是因为HashMap不会在尾部附加新元素,而是在头部附加新元素。因此,当重新散列发生时,它会读取每个元素并将其插入头部的新桶中,然后继续从新地图头部的旧地图中添加下一个元素,从而导致链表颠倒。
如果有多个线程处理相同的哈希映射,则可能导致无限循环。
说明无限循环如何在上述情况下发生的详细解释可以在这里找到:
阅读本文以获得更多理解
如果映射中插入的元素必须根据键进行排序,那么可以使用TreeMap。但是如果键的顺序无关紧要,HashMap会更有效。
内部数据结构重建。来自文档:https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html:
当哈希表中的条目数量超过负载因子和当前容量的乘积时,哈希表被重新散列(即重建内部数据结构),以便哈希表具有大约两倍的存储桶数量。