/**
* Implements Map.put and related methods
*
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent if true, don't change existing value
* 如果这个参数为true,散列表当中已经存在要插入的key,就不插了,
* @param evict if false, the table is in creation mode.
* @return previous value, or null if none
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
//tab 引用当前HashMap的散列表
Node<K,V>[] tab;
//p 表示当前散列表的元素
Node<K,V> p;
//n表示当前散列表数组的长度
//i表示路由寻址的结果
int n, i;
/* 如果table为空,或者数组当前长度为0,说明没有创建HashMap,要先创建
也说明了HashMap在插入第一个元素的时候才初始化,而不是定义出来才开始初始化
延迟初始化逻辑
*/
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
//路由算法 (n-1) & hash == hash%n (n必须为2的次方数)
//如果这个位置为null,则说明其中没有数据,直接放进去
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
//这个位置已经有数据了
else {
//e:临时节点
//k:表示临时的一个key
Node<K,V> e;
K k;
//p在上面的if语句中赋值,代表对应数组下标的元素
//hash值相同并不一定代表值相同,但如果hash值不相同,值一定不相同
//表示桶位中的元素该元素,和你当前插入的key完全一致,表示后续需要进行替换操作
if (p.hash == hash &&
// 判断基本类型的key值是否相同,直接使用等于判断 || 判断非基本类型的key值是否相同,要使用equals
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
//e值为key值相等的这个元素
//key值不相等,且已经发生树化=>红黑树
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
//不是树,且key不相等,剩下一种情况=>链表
//链表的头元素和key不一致,则要遍历整个链表,找到key值就替换,不然就在链表末尾插入
else {
for (int binCount = 0; ; ++binCount) {
//遍历整个链表
if ((e = p.next) == null) {
//一直遍历到空都没有找到key值相等,在表尾插入一个新节点
p.next = newNode(hash, key, value, null);
//TREEIFY_THRESHOLD为树化阈值,默认为8
//因为binCount从0开始,所以当binCount为7的时候,已经有八个节点了,binCount在for循环结束的时候才自增,因此要和树化阈值-1作比较
//当大于等于阈值的时候,链表树化
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
//此时e中存储的为null
break;
}
//判断key值是否相同,逻辑与上面一样
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
//此时跳出e中存储的是key相同的那个地址
p = e;
}
}
//只有替换操作会进入整个if,插入操作中e的值为null
if (e != null) { // existing mapping for key
//将原来对应的value值存起来
V oldValue = e.value;
// onlyIfAbsent为false时 或者 原来key对应的value为空值的时候,e.value被赋值为新的value
// 即如果onlyIfAbsent传入的值为true且oldvalue不为空,不执行此if操作,value没有被插入,没有发生替换操作
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
//返回值为oldvalue,即被覆盖的value值
return oldValue;
}
}
//modCount表示散列表结构被修改次数,替换操作不会走到这里。
++modCount;
//size是散列表中元素的个数,如果大于扩容阈值,会触发扩容
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
HashMap ---- putVal()详解
最新推荐文章于 2024-04-21 20:24:35 发布