Map<String,String> map = new HashMap<>();
map.put("key","value");
//以put为接入点,debug查看过程
第一步调用put
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
第二步hash方法
static final int hash(Object key) {
int h;
//高16低16异或运算,减少hash碰撞
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
第三步putval方法
/**
* hash就是经过扰动的hashcode
* key 就是存入的key
* value 就是存入的value
* onlyIfAbsent if true,相同的key不会插值了,这里默认为false,
* @Override 这个方法是true
* public V putIfAbsent(K key, V value) {
* return putVal(hash(key), key, value, true, true);
* }
* evict为false,则hashmap的table处于创建模式
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
// tab指代是hashmap的散列表再,在下方初始化,hashmap不是在创建的时候初始化,而是在put的时候初始化,属于懒初始化
// p表示当前散列表元素
// n表示散列表数组长度
// i表示路由寻址的结果
Node<K,V>[] tab; Node<K,V> p; int n, i;
//判断是否为空,为空的话初始化,不为空对tab和n进行赋值
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;//正的创建散列表,初始化入口,同时对n赋值
//这个i就是(n-1)和hash做与运算得到的位置,p就是这个位置的Node元素
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);//当这个位置为空,直接封装key和value,放入tab中
else {
//e 临时的node元素
//k 表示临时的一个key
Node<K,V> e; K k;
//表示这个桶的位置的元素的key和将要插入的key是一个,会进行替换
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
//当前节点是红黑树的节点,加入树中,instanceof 判断对象是不是谁的实例,返回boolean类型的值
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
//链表的情况,而且链表的头元素与我们要插入的key不一致
else {
for (int binCount = 0; ; ++binCount) {
//判断到最后也没有key是一样的,就在最末尾插入一个新的节点
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
//在插入完第九个节点,会进行树化
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);//树化函数
break;
}
//条件成立就是在遍历链表中有相同的key,直接跳出
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
//这种属于覆盖操作,当e中有值进入操作
if (e != null) { // existing mapping for key
//oldValue保存老的值,方便return
V oldValue = e.value;
//onlyIfAbsent传入的是false,指定能进入判断
if (!onlyIfAbsent || oldValue == null)
e.value = value;//值的替换
afterNodeAccess(e);
return oldValue;
}
}
++modCount;//增加修改次数
if (++size > threshold)//插入新元素,size自增,大于扩容阈值会触发扩容
resize();//扩容
afterNodeInsertion(evict);
return null;
}
/**
* 谁知道afterNodeAccess(e);和afterNodeInsertion(evict);的作用欢迎留言,我是没看明白这个。
*
*/