put()方法用于对HashMap中添加元素如果添加的位置为空则直接添加 , 如果有值存在则覆盖并返回该值
public V put(K key, V value) {
// 调用putVal方法添加元素 并返回被覆盖的值
return putVal(hash(key), key, value, false, true);
}
putVal()方法源码分析
final V putVal ( int hash, K key, V value,boolean onlyIfAbsent, boolean evict){
// 声明局部变量tab,局部变量Node类型p,int类型n,t
HashMap.Node<K, V>[] tab;
HashMap.Node<K, V> p;
int n, i;
// 先将当前hashMap中的table赋值给tab,判断tab是否为空或长度为0
if ((tab = table) == null || (n = tab.length) == 0)
// 如果table为空或长度为0说明还没有创建哈希表,需要创建一个默认长度为16的哈希表
n = (tab = resize()).length;
// i = (n - 1) & hash 将需要插入数据位置的对应数据取出
// p = tab[i = (n - 1) & hash]) 并赋值给p
// 如果为空说明当前位置没有数据可以直接插入(p为当前hashMap中数组上的一个节点)
if ((p = tab[i = (n - 1) & hash]) == null)
// 将数据直接插入到数组中
tab[i] = newNode(hash, key, value, null);
else {// 需要插入的位置不为空 说明需要插入的位置有内容需要向后遍历然后插入
// 声明一个Node节点e 和 key k
HashMap.Node<K, V> e;
K k;
// 判断需要插入的位置是不是p(如果p的哈希值等于传入的哈希值并且p的key与传入key相等 , 或者传入的key不为空且传入key与p的key相等)
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
// 相等则将p赋值给e , e p
e = p;
// 如果p节点时树节点则调用TreeNode.putTreeVal方法插入节点
else if (p instanceof HashMap.TreeNode)
e = ((HashMap.TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
// 以上都不是则说明p节点是一个链表的头结点 , 需要插入的节点位置在链表上
else {
// 遍历找到需要插入的节点
for (int binCount = 0; ; ++binCount) {
// 如果p的下一个节点为空则插入节点 , 并将下一个节点赋值为e
if ((e = p.next) == null) {
// 为e赋值
p.next = newNode(hash, key, value, null);
// 如果循环次数大于等于7(TREEIFY_THRESHOLD - 1)则将链表转换为红黑树
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
// 如果e的哈希值等于传入的哈希值并且e的key与传入key相等 , 或者传入的key不为空且传入key与e的key相等
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
// 说明找到了需要替换value的节点 , 直接退出循环
break;
// 以上情况都不是则继续进行遍历 , 将p.next赋值p
p = e;
}
}
// 如果插入节点不为空
if (e != null) { // existing mapping for key
// 将需要被覆盖的value赋值给oldValue
V oldValue = e.value;
// onlyIfAbsent控制是否改变现有值 , 如果onlyIfAbsent为ture则不改变值
if (!onlyIfAbsent || oldValue == null)
// 将传入的value赋值给e的value
e.value = value;
// afterNodeAccess();是linkedHashMap的方法 , 在hashMap中方法体为空
afterNodeAccess(e);
// 返回被覆盖的value
return oldValue;
}
}
// Map的操作次数+1
++modCount;
// 如果当前的size长度大于当前hashMap需要扩容的长度时对数组进行扩容
if (++size > threshold)
resize();
// afterNodeInsertion(); 是linkedHashMap的方法 , 在hashMap中方法体为空
afterNodeInsertion(evict);
// 被插入节点为空 , 或被插入节点值为空时返回null
return null;
}
}