HashMap原始碼分析 一 逐行分析

2022-09-04 12:24:12 字數 3009 閱讀 5821

首先,我們要了解一下hashmap的儲存方式

既然名字包含hash,不難看出他是以hash值作為位址儲存的,更確切的講他是以雜湊桶aka鏈位址的方式儲存元素的

如果不了解什麼是雜湊桶,或者想先看一下hashmap的實現特點參見——hashmap實現特點——基於jdk文件

雜湊衝突採用的是雜湊桶,桶中元素使用鍊錶儲存,但是如果元素過多,那麼就會採用樹的方式儲存。樹是hashmap中最重要的資料結構。

hashmap()構造方法

putval()方法

resize()方法

hashmap是按照下面圖示方式儲存元素(如果沒有雜湊衝突),乙個陣列,陣列中元素叫做節點也就是桶,所以首先我們需要了解節點。如果有雜湊衝突,那麼每個節點的桶就會存多個元素,文章下面有。

下面是內部類node:

static class nodeimplements map.entry

public final k getkey()

public final v getvalue()

public final string tostring()

public final int hashcode()

public final v setvalue(v newvalue)

public final boolean equals(object o)

return false;}}

可以看到,是乙個很常見的節點的表達方式,下面這個圖就沒有寫hash,因為hash使用制定存放位址的,這裡的next一般是為了解決雜湊衝突而設定的,本篇文章下面還有一幅圖更詳細

新建hashmap物件後,只有使用它,它才會初始化,也就是put語句,使用put後

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

boolean evict)

所以由於table為空,所以初始化也就是執行resize方法,tab = resize();呼叫了resize()方法

繼續向下看:

final node resize() 

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

oldcap >= default_initial_capacity)

newthr = oldthr << 1; // double threshold

}@pass

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

newcap = oldthr;

else

@pass

if (newthr == 0)

threshold = newthr;

//threshold初始化了

//開始新建乙個node陣列,大小為newcap

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

//table賦予值

table = newtab;

@pass

//下面**也被省略

return newtab;

}

目前就完成了初始化,得到乙個預設容量的鍊錶,然後繼續執行putval方法

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

//...也省略

return null;

}

// create a regular (non-tree) node

nodenewnode(int hash, k key, v value, nodenext)

可以看到他是建立節點的函式,繼續呼叫node的構造方法,上面已經介紹了node和它的構造方法,所以返回了乙個新的節點,由於這是第乙個節點,也就是頭節點。繼續新增節點和上面步驟一樣,不過需要注意的是,當遇到hash衝突時,也就是我們要存放乙個元素,根據其hash值存放,不過檢測到原節點陣列該位置已經有元素,並且他們兩個的key值不一樣,這就遇到了hash衝突,所以我們會執行雜湊桶,也就是鏈位址法去解決衝突,如果不了解雜湊桶,可以參見我另一篇文章;

下面我介紹一下雜湊衝突元素的新增:(從第乙個雜湊衝突介紹)

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

boolean evict)

}//執行

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衝突的解決方案。如果雜湊桶中元素過多會使用樹去代替鍊錶,樹在hashmap中是很重要的乙個結構,足足佔了600行**。以後會專門講解。

HashMap原始碼分析 一

還是從我們使用者的角度一步一步來分析吧。首先我們一般 map map new hashmap 構造方法原始碼如下。其實只是初始化了乙個裝載因子,這個變數幹啥用的呢?loadfactor譯為裝載因子。裝載因子用來衡量hashmap滿的程度。loadfactor的預設值為0.75f。計算hashmap的...

逐行分析jQuery原始碼

注意 本次原始碼分析選擇2.0.3 因為不支援ie6 7 8,就少了很多相容的hack的寫法,對了解jquery的實現原理有很大的幫助 1.jquery有不同的版本,從2.x版本便不再支援ie6 7 8 將jquery拆分長框架一點一點進行了解 2.function 這個叫匿名函式自執行 3.匿名函...

HashMap原始碼分析

public hashmap int initialcapacity,float loadfactor 2 接下來是重要的put方法,put方法用於將鍵值對儲存到map中,讓我們來具體分析一下。public v put k key,v value if key null 若key為null,則將va...