1、HashMap put 一个元素会引起什么
JDK1.7中:创建HashMap时并不为table数组初始化(即创建时table是空数组),在第一次进行put操作的时候,才会进行初始化
过程分为如下几个阶段:
-
table初始化:第一次进入put方法,如果table = {} (即数组还没有初始化),那么进行初始化操作
-
key判NULL:如果key为null,那么调用putForNullKey(value)方法,找到遍历table[0]寻找key = null,替换value值,如果找不到,就在该桶上增加一个(null,value)的结点,采用头插法
-
根据key寻找桶:
- 调用hash(key)方法算出该key对应的hash值
- 调用indexFor(hash, table.length)方法,根据hash值和数组长度算出桶的下标(数组下标)
-
遍历 i 号桶:
- 遍历该桶链表的结点
- 如果 该结点的hash值 = key的hash值 && key相等或者key的equals相同,就用value替换旧值,并返回旧的value值
- 如果 遍历完都找不到该key对应的结点,就进行下一步操作
-
添加Node结点:
- modCount++;
- 调用addEntry(hash, key, value, i)方法
- 首先判断是否需要扩容(size大于扩容阈值,当前桶不 = NULL),
- 就进行扩容操作,调用resize
- 先保存旧数组,如果旧数组的容量达到了最大容量,就不进行扩容,阈值直接设置整数的最大值,直接返回
- 根据新容量创建新数组newTable
- transfer(newTable, initHashSeedAsNeeded(newCapacity))方法,讲旧数组的结点转移到新数组上,旧数组置空(这里存在一个唤醒链表导致进行get方法时会发生死循环)
- table = newTable;设置扩容阈值 threshold =(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1)的最小值
- 重新求hash值
- 重新求桶的位置 (i)
- 就进行扩容操作,调用resize
- 调用createEntry(hash, key, value, bucketIndex)方法,利用头插法在第 i 个桶上插入新结点
- 首先判断是否需要扩容(size大于扩容阈值,当前桶不 = NULL),
- return null;(没有旧的value)