关于HashMap的疑问
JDK8 HashMap数据结构
1 |
|
不难发现HashMap底层由数组、链表和红黑树三者组成。
Node类
包含一个执行自身类型的引用next,显然Node类是组成链表的节点,next引用负责链接各个节点。
table数组
Node类组成的数组,装载所有的键值对。table有以下几个特点:
- 长度N一定为2的幂。即使指定初始长度,N一定是大于等于初始长度的2的幂(可以参考tableSizeFor函数)
- table[i]包含的是hash&(N-1)的Node节点。由于N为2的幂,hash&(N-1)等价于hash%N。与运算的速度大大高于取余,这就是作者的高明之处。
- 延迟初始化,只用第一次在Map中放入元素时,才会调用这个分配空间。
链表和红黑树
多个元素hash&(n-1)的值相同的情况称为hash碰撞。链表和红黑树这两种数据结构都是在发生hash碰撞时产生的结果。如果链表的长度大于8且table长度大于64,链表被转化为红黑树。如果红黑树的节点数量小于6,则转化为链表。
HashMap重要字段
Node
[] table,文章已经提到不再赘述 DEFAULT_INITIAL_CAPACITY = 1 << 4。HashMap默认初始大小为16
DEFAULT_LOAD_FACTOR = 0.75f。默认负载因子是0.75,也就是说table数组有75%非空时进行扩容。
size:记录Map中键值对个数。
threshold:记录下一次扩容的阈值。threshold = loadFactor * table.length.
重要的函数
get操作实现函数getNode
1 |
|
put操作实现函数putVal
1 |
|
扩容函数resize
1)获取新数组newTab的长度,为newTab申请空间。需要考虑容量最大边界,延迟初始化等问题。
2)将原数组oldTab中的节点,放入newTab中。链表和红黑树拆解问题。数组容量是2的幂,所以拆解过程很有技巧
1 |
|