常见概念
- HashMap默认容量为16,负载因子为0.75
- HashMap要求容量必须是2的幂次
- 在JDK1.8及以后,若链表元素个数大于等于8时,链表转换成树结构;若链表元素个数小于等于6时,树结构还原成链表(为什么HashMap链表长度超过8会转成树结构)
- JDK1.7用的是头插法,而JDK1.8及之后使用的都是尾插法(一文读懂HashMap2、3章节)
HashMap的数据结构
HashMap什么时候扩容?
1.7扩容必须满足两个条件:
- 存放新值的时候当前已有元素的个数必须大于等于阈值(容量*负载因子)
- 存放新值的时候当前存放数据发生hash碰撞(当前key计算的hash值换算出来的数组下标位置已经存在值)
1.8扩容(满足任意条件即会触发):
- 存放新节点结束之后,当前已有元素的个数必须大于等于阈值(容量*负载因子)
- 判断树化的时候
HashMap扩容
HashMap的put和get方法原理
HashMap多线程下发生死循环的原因
Hashmap1.7和1.8有哪些区别
Hashmap为什么大小是2的幂次?
static int indexFor(int h, int length) {
// assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
return h & (length-1);
}
从源码可以看出,在计算元素存放的位置的时候,用的是元素的hashcode与当前map长度-1进行与运算。
如果map长度为2的幂次,那长度-1的二进制一定为1111…这种形式,进行与运算就看元素的hashcode;但是如果map的长度不是2的幂次,比如为15,那长度-1就是14,二进制为1110,无论与谁相与最后一位一定是0,0001,0011,0101,1001,1011,0111,1101这些位置就永远都不能存放元素了,空间浪费相当大。也增加了添加元素是发生碰撞的机会。减慢了查询效率。所以Hashmap的大小是2的幂次。返回↑