HashMap 原始碼深度解析

2021-09-04 07:02:15 字數 2505 閱讀 5646

hashmap 的底層使用 陣列+單項鍊表,jdk1.8後,當鍊表過長時,會將鍊錶轉成紅黑樹,時間複雜度由 o(n) 變成了 o(logn),同時,hashmap 是執行緒不安全的。

public v put(k key, v value)
a、對 key 求 hash 值。計算下標(通過 hash(object key) 方法);

hash(object key)方法:

對key值進行hash運算,h >>> 16表示右移16位,即:hash值後16位與前16位進行或運算。

目的是為了均衡得到的結果,減少hash碰撞的概率 (假如說對key的hash值進行0-15的取餘,可能會出現某乙個鍊錶會有非常多的數值存在(例如:16,32,48對15取餘結果都是1,所以這些資料都會儲存在陣列的第二位,形成乙個長度為3的鍊錶,而陣列的其他15位都空置),這樣會增加運算的複雜度,還會造成資源的浪費!)

static final int hash(object key)
b、判斷陣列是否為空,為空執行 resize() 進行擴容;

c、根據鍵值key計算hash值得到插入的陣列索引i,如果 table[(n - 1) & hash]==null,(n - 1) & hash 得到 node 節點的位置,為空直接新建節點;

d、否則,看是否 hash 碰撞:

如果沒有碰撞,直接放入桶中;

如果發生碰撞,以鍊錶的形式鏈結到鍊錶的末尾(1.8之前是鏈結到頭部);

如果鍊錶長度超過閾值(treeify_threshold = 8),鍊錶會轉成紅黑樹,如果 key 已經存在就替換舊值;當移除元素時,如果鍊錶長度低於閾值(untreeify_threshold = 6),紅黑樹會轉變為鍊錶;

e、成功,判斷當前容量,如果桶滿了(容量* 負載因子0.75),就需要 resize()擴容;

下圖**於網路:

原始碼如下:

final v putval(int hash, k key, v value, boolean onlyifabsent,

boolean evict)

if (e.hash == hash &&

((k = e.key) == key || (key != null && key.equals(k))))

break;

p = e;}}

v oldvalue = e.value;

if (!onlyifabsent || oldvalue == null)

e.value = value;

afternodeaccess(e);

return oldvalue;}}

++modcount;

if (++size > threshold)

resize();

afternodeinsertion(evict);

return null;

}

新陣列容量擴充為原來的兩倍,然後對每個節點重新計算 hash 值,這個值可能並且僅可能是在原下標位置或者是下標為 < 原下標 + 原容量 > 的位置,原始碼如下:

final node resize() 

else if ((newcap = oldcap << 1) < maximum_capacity &&

oldcap >= default_initial_capacity)

newthr = oldthr << 1; // double threshold

}else if (oldthr > 0) // initial capacity was placed in threshold

newcap = oldthr;

else

if (newthr == 0)

threshold = newthr;

@suppresswarnings()

node newtab = (node)new node[newcap];

table = newtab;

//生成乙個新陣列,將舊陣列的資料進行遷移

if (oldtab != null)

else

} while ((e = next) != null);

if (lotail != null)

if (hitail != null) }}

}}return newtab;

}

通過 put 方法相同的 hash 演算法

public v get(object key)
獲取節點

final nodegetnode(int hash, object key)  while ((e = e.next) != null);}}

return null;

}

HashMap原始碼解析

以jdk1.8為例,hashmap是乙個用於儲存key value鍵值對的集合,每乙個鍵值對是乙個node jdk1.7叫做entry 後台是用乙個node陣列來存放資料,這個node陣列就是hashmap的主幹。這裡我們主要來分析hashmap的get和put方法。public v put k k...

hashMap 原始碼解析

這幾天跳槽 被人問得最多的問題就是基礎方面的知識.當時學習的時候有點囫圇吞棗.現在回頭把這些基本的集合類原始碼都仔細閱讀下 hashmap 用的是最頻繁的.所以問得也最多了.initcapacity 初始化的容量 loadfacotr 負載因子 主要用來計算threshold的值 threshold...

HashMap原始碼解析

預設字段 static final int default initial capacity 1 4 預設node的陣列長度 16 static final int maximum capacity 1 30 陣列的最大長度 2 30 static final float default load ...