HashMap插入节点详细过程

Posted 小谢backup

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HashMap插入节点详细过程相关的知识,希望对你有一定的参考价值。

下面先给出HashMap的草图,方便理解:


Java1.8中HashMap插入的过程流程图如下:



大致总结一下,除了特殊情况判断之外,插入节点到HashMap过程中,首先计算节点的哈希后找到对应的位置(槽),如果该槽为空,直接插入即可,否则顺着该槽沿伸出来的链表或者红黑树遍历到尾部然后插入,如果中途遇到相同key冲突的情况就替换掉旧的Node。


具体代码实现如下(已做部分注释):


 1 /**
2  * 插入新节点
3  * @param  onlyIfAbsent 只有槽为空的情况才插入,遇到相同key冲突的情况不可替换(即舍弃要插入的node),put时为false
4  */

5 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
6               boolean evict
{
7    Node<K,V>[] tab; Node<K,V> p; int n, i;
8
9    if ((tab = table) == null || (n = tab.length) == 0)//如果map为空,直接扩容后返回
10        n = (tab = resize()).length;
11
12    if ((p = tab[i = (n - 1) & hash]) == null)//如果槽为空,直接放入
13        tab[i] = newNode(hash, key, valuenull);
14    else {
15        Node<K,V> e; K k;
16        if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))//槽中node的key与插入node的key相等,直接到下面的if (e != null) 语句块
17            e = p;
18        else if (p instanceof TreeNode)//属于红黑树节点,按红黑树的方式插入
19            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
20        else {//分支链表形式插入
21            for (int binCount = 0; ; ++binCount) {//dead loop,条件在内部,binCount表示链表长度(从0开始)
22                if ((e = p.next) == null) {//短链表的最后一个节点,则插入,插入后判断是否应该转为红黑树,完成。
23                    p.next = newNode(hash, key, valuenull);
24                    if (binCount >= TREEIFY_THRESHOLD - 1)//如果长度为8,转为红黑树
25                        treeifyBin(tab, hash);
26                    break;//完成插入后退出
27                }
28                if (e.hash == hash &&
29                    ((k = e.key) == key || (key != null && key.equals(k))))//链或者树已有相同key存在,退出??
30                    break;
31                p = e;
32            }
33        }
34
35        if (e != null) { // 槽中node(p)的key与插入node的key相等,直接覆盖该槽的node(直接换新值就好了)
36            V oldValue = e.value;
37            if (!onlyIfAbsent || oldValue == null)
38                e.value = value;//覆盖旧值
39            afterNodeAccess(e);
40            return oldValue;
41        }
42    }
43
44    //必做善后
45    ++modCount;
46    if (++size > threshold)//插入后预先判断是否下一次插入会不会越界,如果会就扩容
47        resize();
48    afterNodeInsertion(evict);
49    return null;
50}


以上是关于HashMap插入节点详细过程的主要内容,如果未能解决你的问题,请参考以下文章

HashMap 和 ConcurrentHashMap 的区别

HashMap底层源码解析上(超详细图解+面试题)

HashMap死循环分析的修正版

LinkedHashMap源码

平衡二叉树插入操作的详细过程图解

SAPUI5 如何在语义详细视图中插入片段或 xmlview