按部就班分析源碼 - HashMap put 方法的執行流程(jdk 1.8 )

前言

本篇博客主要分析下 jdk1.8 中 HashMap 的 put 方法的執行流程。主要經過代碼註釋和畫流程圖的方式來說解。java

關於本篇博客的幾點說明算法

正文

預備知識

注意:這裏不會講紅黑樹是什麼,以及如何具體實現。咱們只需知道它長什麼樣子並瞭解它的好處便可。數組

爲何 在jdk1.8 中採用數組+鏈表/紅黑樹的數據結構存儲數據?數據結構

當 Hash 衝突嚴重時,在數組上的鏈表會愈來愈長,此時就會會下降查詢時的效率;時間複雜度爲 O(N)。 引入紅黑樹以後查詢效率直接提升到了 O(logn)。this

引入紅黑樹後,HashMap 內部數據結構長什麼樣子?.net

java8中HashMap數據結構

何時會採用鏈表,何時用紅黑樹?code

當鏈表的大小大於預設的閾值(8)時就要轉換爲紅黑樹blog

put 方法源碼(帶註釋)

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; // 局部變量,指向容器
    Node<K,V> p; // 局部變量
    int n, i;
    // 1. 若是 HashMap 沒有初始化,須要進行初始化
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    // 2. 根據計算出的元素所在數組中的位置,並判斷目標位置是否爲空
    // 2.1 若是爲空. new 一個新的 Node 放置在目標位置
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    // 2.2 若是不爲空, 再分狀況討論
    else {
        Node<K,V> e; 
        K k;
        // 2.2.1 若是目標位置有值(有多是紅黑樹的根節點,也有多是鏈表的表頭),就比較key 是否相同(至關於提早判斷吧)
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        // 2.2.2 若是目標位置放的是一個紅黑樹,就按照紅黑樹的方式,寫入數據
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        // 2.2.3 若是目標位置放置的是一個鏈表,就遍歷整個鏈表。
        else {
            for (int binCount = 0; ; ++binCount) {
            	// 若是當前節點的下一個節點爲空,就 new 一個新的節點,而後當前節點指向這個新節點
                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;
            }
        }
        // 對 2.2.1 和 2.2.2 和 2.2.3 進行判斷。判斷成立表示要覆蓋原有位置的元素。
        if (e != null) { 
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    // 下面是擴容代碼,暫時忽略
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

put 方法的流程圖

jdk1.8 HashMap 的put方法執行流程

總結

本篇文章仍舊只是講了 put 方法的執行流程,沒有過多講原理以及 HashMap 中某一部分爲何這樣作。 後續的文章會逐一補充。get

相關文章
相關標籤/搜索