HashMap之put get remove方法源码分析
注意一点:put时候去扩容 一是需要判断table是否为null 不为null的情况 去扩容 一是要达到阈值 而是要table长度要大于16
1.put(方法):
//计算key值的hash 然后去做put
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
put过程:
1.先去判断数组是不是为null 如果为null则初始化扩容
2.计算出来的Hash存在的数组首节点是否为Null 如果为null则创建新node
3.如果不为null 则表示发生了碰撞,先判断链首位是否相等(hash一样 key一样)(涉及到hashcode 和equls知识点)
如果不等要去判断是不是树类型 如果是树类型 则以树的方式去put
如果不是树的类型 则表示是链表 则在链表的尾部(判断最后一个节点为null)添加新节点
如果相等并且判断当前节点数是否超过7了 ,如果超过7需要转化成树化
4.如果这个key已经存在了 要去根据onlyIfAbsent属性来判断是否需要覆盖旧值
5.如果加入了新节点 则需要改变表结构 modcount++
hashmap节点个数+1,并判断是否超过阈值,如果超过则重建结构!
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 为null 则去初始化 扩容
if ((tab = table) == null || (n = tab.length) == 0)
//给table变量作初始化
n = (tab = resize()).length;
//如果该下标没有值 则创建个新node
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
//如果有值 发生碰撞
Node<K,V> e; K k;
//key 一样 刷新node
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
//如果是红黑树 则需要往树里插节点
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
// 3. 不是TreeNode类型,则表示是一个链表,这里就类似与jdk1.7中的操作
else {
for (int binCount = 0; ; ++binCount) {/// 遍历链表
// 在原来的node创建个新的node p.next->new node
if ((e = p.next) == null) {//
p.next = newNode(hash, key, value, null);
//// 此时查找当前链表的次数已经超过7个,则需要链表RBT化!(变成红黑树类型)
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
//找到链表中对应的节点 赋值
break;
p = e;
}
}
// 如果e不为空,则表示在HashMap中找到了对应的节点
if (e != null) { // existing mapping for key
V oldValue = e.value;
//// 当onlyIfAbsent=false 或者key对应的旧value为空时,用新的value替换旧value
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
//// hashmap节点个数+1,并判断是否超过阈值,如果超过则重建结构!
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
2.get(方法):
//计算key值的hash 然后去做get
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
get过程:
/**
* 1.先计算出hash值
* 2.先去判断table是否为null并且链首位是否为null 如果为null 则直接返回Null
* 3.先判断链首位的hash值和key是否相等 如果相等则直接返回
* 4如果不相等 则去判断类型 如果为红黑树 则以红黑树的方式去查找
* 5.如果不是红黑树 则以链表的形式循环查找
* 6.找到直接返回 没有返回null
*/
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
//先是判断一通table是否为空以及根据hash找到存放的table数组的下标,并赋值给临时变量
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
////总是先检查数组下标第一个节点是否满足key,满足则返回
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
///如果第一个与key不相等,则循环查看桶
if ((e = first.next) != null) {
//检查是否为树节点,是的话采用树节点的方法来获取对应的key的值
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
//do-while循环判断,直到找到为止
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
3.remove(方法):
//计算key值的hash 然后去做remove
public V remove(Object key) {
Node<K,V> e;
return (e = removeNode(hash(key), key, null, false, true)) == null ?
null : e.value;
}
/**
* 1.先去看table是否为null 链首位是否为null 如果为null 直接返回null
* 2.先判断链首位是否key hash都相等 如果相等 找到该节点
* 3.如果不等 去判断是否为红黑树类型 如果是 则以红黑树的方式找到该节点
* 4.如果不是红黑树类型 则循环链表找到该节点
* 5.如果找到了该节点 则去作删除动作(两种不同的删除方式 以红黑树的方式去删除(红黑树如果小于6阈值 要转换成链表))
* 6.modcount++ 表length-1
*/
final Node<K,V> removeNode(int hash, Object key, Object value,
boolean matchValue, boolean movable) {
Node<K,V>[] tab; Node<K,V> p; int n, index;
////老规矩,还是先判断table是否为空之类的逻辑,注意赋值操作
if ((tab = table) != null && (n = tab.length) > 0 &&
(p = tab[index = (n - 1) & hash]) != null) {
Node<K,V> node = null, e; K k; V v;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
node = p;
else if ((e = p.next) != null) {
if (p instanceof TreeNode)
node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
else {
do {
if (e.hash == hash &&
((k = e.key) == key ||
(key != null && key.equals(k)))) {
node = e;
break;
}
p = e;
} while ((e = e.next) != null);
}
}
//找到相应节点 作删除动作
if (node != null && (!matchValue || (v = node.value) == value ||
(value != null && value.equals(v)))) {
if (node instanceof TreeNode)
((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
///如果p == node,说明该key所在的位置为数组的下标位置,所以下标位置指向下一个节点即可
else if (node == p)
tab[index] = node.next;
else
//否则的话,key在桶中,p为node的上一个节点,p.next指向node.next即可
p.next = node.next;
++modCount;
--size;
afterNodeRemoval(node);
return node;
}
}
return null;
}
学习资料:
https://blog.csdn.net/qq_28523617/article/details/77533097
http://www.cnblogs.com/PoorGuy/p/10397346.html
http://www.cnblogs.com/bruceChan0018/p/8033897.html
https://blog.csdn.net/crazy1235/article/details/75579654
https://www.cnblogs.com/finite/p/8251587.html

浙公网安备 33010602011771号