HashMap是用于存储Key-Value键值对的集合, 每一个键值对也叫作一个Entry。所以HashMap底层是由数组加单向链表构成的, 默认的初始长度为16, 每次自动扩容或是手动初始化时候长度必须是2的幂;
为什么初始化长度为16 ?
Return h & (length - 1);
下面我们以“book” 作为key演示一下: book通过 hashCode,十进制结果为3029737,二进制101110001110101110 1001,
通过 & 运算默认长度为16 ,length – 1 就是 15, 转换为二进制 1111 ,
101110001110101110 1001 & 1111 = 1001,十进制是9, 所以index = 9 ,
假设HashMap长度为10 重复上面的运算步骤
hashCode : 101110001110101110 1001
length–1 : 1001
index : 1001
单独看这个结果, 从表面上看没有什么问题, 换一个数试一下
hashCode : 101110001110101110 1011
length – 1 : 1001
index : 1001
这里就能看出, 虽然hashCode数变化的但是当长度为为10的时候结果都是为1001,这样就会造成index结果出现几率变大, 而有些index的结果永远不会出现,比如说0111;
反过来看 16或者是2的幂的数值, length – 1 的值转换为二进制全部都是1, 只需要hashCode本身计算的值比较均匀, 那么Hash算法的结果就是均匀的;
HashMap是怎么扩容的?
在高并发情况下, 首先要明白 ReHash 的概念
ReHash其实就是HashMap在扩容时候的一个步骤
HashMap的容量是有限的, 当经过多次元素插入达到扩容因子0.75时候就会扩容, 这个时候就会扩容就是 resize
影响发生resize的元素有两个:
1. Capacity 指的是当前hashMap的长度;
2. LoadFactor 负载因子, 默认是0.75
上图if判断里面 HashMap.Size >= Capacity * LoadFactor
HashMap的resize方法不是简单的把长度扩大,而是经过了两个步骤
1. 扩容创建一个新的Entry数组, 长度是原来的两倍
2. ReHash 遍历原来的Entry数组, 把原数组所有的的值重新导入新的Entry数组中
HashMap为什么是线程不安全的
在单线程下扩容是没有问题的, 但是在多线程并发环境中,HashMap的ReHash操作就会带来问题
详细可见 : https://www.jianshu.com/p/1e9cf0ac07f4
for循环循环的是当前的数组,