1. 程式人生 > >HashMap內部實現原理

HashMap內部實現原理

   HashMap的底層是基於陣列+連結的一個複合資料結構,非同步的 允許null鍵值 繼承於map介面來實現,通過put和get方法來進行資料的操作.陣列被分為一個個的bucket.雜湊值決定了鍵值對在陣列中的位置.具有相同雜湊值的鍵值對會組成連結串列,當連結串列長度超過閥值(8)的時候回觸發樹化,連結串列轉換成紅黑樹.

20180114111559

    HashMap有幾個關鍵變數:1,initialCapacity 初始化容量,就是hashmap的初始化的儲存空間大小,可以在構造方法裡指定,預設是16.一般是2冪次方, 在hashmap的建構函式中限制了初始化容量是2的n次方.在利用hash碼計算陣列的索引時,一般是用%的方式但這個效率比較低,按位運算特別快.   2,loadFactor   負載因子   hashmap儲存容量滿百分之七十五之後,會進行擴容操作,  增倍   

    原始碼解析:put和get方法

    public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = sun.misc.Hashing.singleWordWangJenkinsHash(key);
        int i = indexFor(hash, table.length);
        for (HashMapEntry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
 
        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

   put(key,value)方法儲存鍵值對物件到hashmap中,首先會通過hashcode方法計算hash值,然後定址到map中bucket位置,如果hash值相同就以連結串列的形式存在bucket後,如果連結串列長度超過閥值就會轉化成紅黑樹.如果陣列長度超過閥值,就呼叫resize方法擴充套件容量.

     get(key)方法獲取儲存在hashmap中的值.也是先獲取hash值定址到bucket的key相等就直接返回,如果發生hash碰撞,有兩種情況,如果是樹 就呼叫getTreenode獲取value. 如果是連結串列就遍歷連結串列查詢對應的value

     resize方法 將陣列擴充套件位原來的兩倍. 重新計算index索引值,將原節點重新放到新的陣列中.這樣也可以把原來衝突的節點分散到新的bucket中

當重新調整hashmap的大小時會存線上程條件競爭的問題,如果兩個執行緒都發現hashmap需要重新調整大小,它們會同時試著調整大小.儲存在連結串列中的次序會反過來,hashmap會將元素放到連結串列頭部,避免尾部遍歷. 如果條件競爭發生,就死迴圈了.  因為hashmap是非執行緒同步的,  多執行緒環境中考慮使用hashtable和ConcurrentHashMap

ConcurrentHashMap和hashmap的實現思路基本相同,也可以說是支援併發操作的hashmap!

ok 關於hashmap的總結大概就這些了. .