上一篇HashMap怎么学(一)我们通过一个简单的例子解释了HashMap的内部结构。
这篇文章我们会在上一篇的例子基础上改进下,给大家解释HashMap的内部数组是怎么扩展的,以及其内部是如何生成链表的。
代码案例
1 | arduino复制代码public static void part2_1() { |
执行完上述代码后HashMap的内部结构变化如图:
HashMap内部结构图2-1
代码解释
- 步骤一执行完后,HashMap内部会生成一个长度为16的数组,数组的前12位的Node对象的key-value值和数组index值相同(HashMap内key-value键值对数量为12)。
- 步骤二执行完后,HashMap的内部数组长度变成原来的2倍(32),并且第12位的Node对象的key-value值也为12。这里涉及到HashMap内部数组的扩张机制:
DEFAULT_LOAD_FACTOR默认值是0.75(也可以通过HashMap构造函数传递),表示当HashMap内key-value键值对数量超过内部数组长度0.75时,对内部数组进行扩张。
执行完步骤一后,内部数组长度为16,当key-value键值对数量超过16×0.75=12时内部数组会进行扩张,下面为HashMap部分源码。
1 | arduino复制代码 /** |
内部数组长度扩展的长度是原值左移一位,也就是乘以2(newCap = oldCap << 1),下面为HashMap部分源码。
1 | ini复制代码final Node<K,V>[] resize() { |
- 步骤三执行完后,原内部数组index为0的Node对象变成了一个链表的头结点。
HashMap是通过tab[i = (n - 1) & hash]来定位新的key-value键值对要插入到内部数组的哪个位置的,这时n为内部数组长度32,n-1对应到二进制为00011111,Integer的hashcode值就是它本身的int值,这时hashcode就发生冲突了,都插入到了index为0的位置,组成了一个链表:
00011111&00000000=0
00011111&00100000(32)=0
00011111&01000000(64)=0
00011111&10000000(128)=0
下面为HashMap部分源码:
1 | ini复制代码final V putVal(int hash, K key, V value, boolean onlyIfAbsent, |
这篇文章就分享到这里,后续还有HashMap其他文章会陆续发布。
大家如果有问题欢迎在评论区留言一起探讨,同时也可以关注收藏“小西学JAVA”和同名公众号,有文章更新会及时收到通知。
Demo代码位置
本文转载自: 掘金