HashMap原始碼分析 JDK1 8

2021-08-10 04:17:30 字數 3552 閱讀 8745

陣列+鍊錶/紅黑樹:陣列儲存元素,當有衝突時,就在該陣列位置形成乙個鍊錶,儲存衝突的元素,當鍊表元素個數大於閾值時,鍊錶就轉換為紅黑樹。

transient node table;

transient

int size;

int threshold;

final

float loadfactor;

// 預設初始容量16

static

final

int default_initial_capacity = 1

<< 4;

// 最大容量2^30

static

final

int maximum_capacity = 1

<< 30;

// 預設負載因子

static

final

float default_load_factor = 0.75f;

// 鍊錶轉紅黑樹的閾值

static

final

int treeify_threshold = 8;

node table的初始化長度length(預設值是16),loadfactor為負載因子(預設值是0.75),threshold是hashmap所能容納的最大資料量的node(鍵值對)個數。threshold = length * loadfactor。也就是說,在陣列定義好長度之後,負載因子越大,所能容納的鍵值對個數越多。

在jdk1.8的實現中,優化了高位運算的演算法,通過hashcode()的高16位異或低16位:

(h =k.hashcode()) ^ (h >>> 16)
從速度、功效、質量來考慮,這麼做可以在陣列table的length比較小的時候,也能保證考慮到高低bit都參與到hash的計算中,同時不會有太大的開銷。

/**

* 計算雜湊值

*/static

final

int hash(object key)

/**

* 計算索引

*/static

int indexfor(int h, int length)

else

具體**如下:

do 

else

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

if (lotail != null)

if (hitail != null)

例:key1=5,key2=21

擴容前:

hash(key1) = 5 mod 16 = 5

hash(key2) = 21 mod 16 = 5

擴容後:

hash(key1) = 5 mod 32 = 5

hash(key2) = 21 mod 32 = 21 = 5 + 16

利用位運算,提高效率:

原容量oldcap= 16,即0001 0000,oldcap-1 = 0000 1111

新容量newcap = 32,即0010 0000,newcap-1 = 0001 1111

判斷對應位是否為1:key & cap

獲取索引:key & (cap - 1)

rehash之後,n為原來的2倍,所以n-1的mask範圍在高位多1bit(紅色),因此新的index就會發生這樣的變化:

// 判斷是否擴容

if (++size > threshold)

resize();

afternodeinsertion(evict);

return

null;

}(2)resize

final node resize() 

12// 沒超過最大值,就擴充為原來的2倍

13else

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

14 oldcap >= default_initial_capacity)

15 newthr = oldthr << 1; // double threshold

16 }

17else

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

18 newcap = oldthr;

19else

23// 計算新的resize上限

24if (newthr == 0)

30 threshold = newthr;

31@suppresswarnings()

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

33 table = newtab;

34if (oldtab != null)

5859

else

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

67// 原索引放到bucket裡

68if (lotail != null)

72// 原索引+oldcap放到bucket裡

73if (hitail != null)

77 }

78 }

79 }

80 }

81return newtab;

82 }

分析HashMap 的 JDK 原始碼

緣由 今天好友拿著下面的 問我為什麼 map.entry 這個介面沒有實現 getkey 和 getvalue 方法,卻可以使用,由此,開啟了一番查閱 jdk 原始碼的旅途 map map new hashmap map.put 1,張三 map.put 2,李四 map.put 3,王五 map....

hashmap原始碼分析jdk8

最近看了下jdk8的hashmap原始碼,相比於7,在儲存結構上有了些改變。1.在jdk8之前,hashmap的儲存結構是陣列 鍊錶的形式,那麼這種方式隨著鍊錶的長度增加,效率也凸顯出來。所以在jdk8中這塊做了優化,當鍊表超過一定長度時轉化為紅黑樹來解決這個問題,下面用流程圖畫出hashmap 的...

HashMap原始碼分析 (JDK1 8

首先,hashmap儲存結構類似於位桶,總體結構是 位桶 鍊錶 紅黑樹,這與之前版本的實現有所改進。常量域預設容量16 static final int default initial capacity 1 4 最大容量2的30次方 static final int maximum capacity...