默认初始长度为16,每次扩容一倍
HashMap在并发插入元素的扩容时,会出现线程安全问题,可能会出现环形链表,让下一次读操作出现死循环
扩容源码
1 | void transfer(Entry[] newTable, boolean rehash) { |
.
该部分参考文章 https://mp.weixin.qq.com/s/dzNq50zBQ4iDrOAhM4a70A
为什么负载因子是0.75?
.
- 当负载因子为1.0时,会产生较多的Hash冲突,红黑树变得比较复杂,查询效率降低
- 当负载因子为0.5时,会增加额外的空间消耗
所以0.75是时间和空间的权衡结果,源码注释中也提到了这一点
为什么链表和红黑树转换的阈值是8?
按照源码解释,**TreeNode
的大小是ListNode
的两倍,所以应该尽量减少使用**
当负载因子为0.75时,链表长度$k$和概率$p$服从$λ=\frac{1}{2}$的泊松分布,即
$$
p(k)=\frac{λ^ke^{-λ}}{k!}=\frac{1}{2^kk!\sqrt{e}}
$$
1 | 0: 0.60653066 |
JDK1.7和1.8的区别
JDK1.7 | JDK1.8 | |
---|---|---|
数据结构 | 数组+链表 | 数组+链表+红黑树(链表长度>8) |
插入方式 | 头插法(LRU思想)(会出现环形链表) | 尾插法 |
扩容 | 链表逆序(头插法导致) | 链表原序 |
rehash | hashCode()->扰动处理->hash&(capacity-1) | 原位置 or 原位置+capacity |
HashMap与HashTable的区别
HashMap | HashTable | |
---|---|---|
并发性 | 主要方法无synchonized关键字 | 主要方法均有synchonized关键字 |
key值是否允许为null | 允许 | NullPointerException |
默认初始容量 | 16 | 11 |
扩容 | *2 | *2+1 |