/**
int hash:根据key计算出来的hash值
k key:key
V value:value
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
// 判断全局的table是否为空
if ((tab = table) == null || (n = tab.length) == 0)
// 如果全局的table为空 就进入初始化容器 默认初始化容器为16 负载因子为0.75f
n = (tab = resize()).length;
// 根据(n-1)&hash值计算出数组的下标 如果定义的p=table[计算的下标]=null
if ((p = tab[i = (n - 1) & hash]) == null)
// 就在此数组下标直接赋值
tab[i] = newNode(hash, key, value, null);
// 如果此数组下标中存在值 不为null 就走else判断逻辑
/**
此时 Node<K,V> p 是有值的
*/
else {
Node<K,V> e; K k;
// 计算此时数组坐标上那个值的hash和key与新增进来的值和hash是否相同
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
// 如果相同 就将数组坐标的旧值 赋值给e
// e是新插入进来的值 p是数组坐标上的值 因为hash计算出来的数组坐标是一样的
// 现在的e就等于:之前的值p
/**
比如:之前的旧值为
p: Node<K,V,NEXT>=YAO,YAOXIANG,NULL
插入进来的新值为:
e: Node<K,V,NEXT>=YAO,YAOXIANG11,NULL
然后计算key相等 hash也相等 就直接
e=p;所以现在的e为旧值 现在就跳第三步
**/
e = p;
// 如果key不相同 就走下面的判断逻辑
// 现在的p为根据新增进来的key计算下标获取的值
/**
instanceof:是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类创建的对象时,返回trur,否则返回false
instanceof 的例子:
public class Code {
public static void main(String[] args) {
Node<Integer> node = new Node<>(1, 2, new Node<>(1, 2, null, 2), 1);
if( node instanceof Node){
System.out.println(true);
}
}
static class Node<T>{
private int key;
private T value;
private Node<T> next;
private int hash;
public Node(int key,T value,Node<T> next,int hash){
this.key=key;
this.value=value;
this.next=next;
this.hash=hash;
}
}
}
*/
// 这里就是判断这里的Node是不是红黑树创建的 如果是就走里面的逻辑 否者跳下面
else if (p instanceof TreeNode)
// 如果此时坐标上的p是红黑树节点 就走这里的逻辑
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
// 如果此时坐标上的p不是红黑树是链表 就走这里的for循环逻辑 遍历链表
for (int binCount = 0; ; ++binCount) {
// 这里就开始遍历链表 判断节点的next是否为null 如果为null就添加到尾节点
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
// 当链表的长度大于等于7的时候 链表变为红黑树 (当红黑树一个阈值的时候 也会变为链表) 链表变红黑树阈值: static final int TREEIFY_THRESHOLD = 8;
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
// 将整个table 和此hash值红黑树化
treeifyBin(tab, hash);
break;
}
// 遍历链表的时候 同时也要判断key是否相同 如果相同就覆盖 返回旧的value值 看第三步
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
// 第三步 e现在不为null e为旧值
if (e != null) { // existing mapping for key
// 记录旧值 返回
/**
所以当hash冲突且key相同时 hashMap.put() 会返回之前的旧值
*/
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
// 这里就是更新旧址 将插入进来的value 替换掉旧值的value
e.value = value;
afterNodeAccess(e);
// 返回旧址的value
return oldValue;
}
}
++modCount;
// 每当新增一个元素的时候 size++ 当size>阈值(负载因子0.75f*容器容量(默认16)=12)的时候就扩容
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}