HashMap原始碼分析及底層原理

2021-10-25 15:22:31 字數 4564 閱讀 3730

原始碼分析:

總結

hashmap map = new hashmap();/i預設情況下,先不建立長度為16的陣列

當首次呼叫map.put()時,再建立長度為16的陣列

陣列為node型別,在jdk7中稱為entry型別

形成鍊錶結構時,新新增的key-value對在鍊錶的尾部(七上八下)

當陣列指定索引位置的鍊錶長度》8時,且map中的陣列的長度》64時,此索引位置上的所有key-value對使用紅黑樹進行儲存。

將k和v封裝到node物件當中(節點)

呼叫k的hashcode()方法得出hash值

通過雜湊表函式/雜湊演算法,將hash值轉換成陣列的下標。做法為hash值對陣列長度取模,當n為2的冪時,等效為hash&(n-1)。這也是為什麼map中陣列長度取為2的整數次冪。

呼叫k的hashcode()方法得出雜湊值,通過雜湊演算法轉換成陣列下標。

通過陣列下標快速定位到某個位置上。

如果這個位置上什麼都沒用,則返回null。

如果這個位置上有單向列表,那麼就會用引數k和單向鍊錶上的每乙個節點的k進行equals比較

hash陣列儲存該node節點的引用,當發生了hash碰撞,解決衝突的辦法為鍊錶法/紅黑樹,也即節點串成乙個鍊錶

static

class

node

implements

map.entry

public

final k getkey()

public

final v getvalue()

public

final string tostring()

public

final

inthashcode()

public

final v setvalue

(v newvalue)

public

final

boolean

equals

(object o)

return

false;}

}

//初始化陣列大小

static

final

int default_initial_capacity =

1<<4;

// aka 16

/*** the maximum capacity, used if a higher value is implicitly specified

* by either of the constructors with arguments.

* must be a power of two <= 1<<30.

*/static

final

int maximum_capacity =

1<<30;

/*** the load factor used when none specified in constructor.

*///負載因子

static

final

float default_load_factor =

0.75f

;//當鍊表數目超過該值,轉換為紅黑樹

static

final

int treeify_threshold =8;

//當紅黑樹節點小於該數目,退化為鍊錶

static

final

int untreeify_threshold =6;

//當陣列數目大於該值,鍊錶與紅黑樹的轉換才優先考慮

static

final

int min_treeify_capacity =

64;

transient node

table;

public

hashmap

(int initialcapacity,

float loadfactor)

//傳入乙個初始容量,預設負載因子0.75

public

hashmap

(int initialcapacity)

//無引數,負載因子預設0.75

public

hashmap()

//傳入乙個map的物件

public

hashmap

(map<

?extendsk,

?extends

v> m)

public v put

(k key, v value)

----

----

----

----

----

----

----

----

----

----

----

----

----

----

--static

final

inthash

(object key)

----

----

----

----

----

----

----

----

----

----

----

----

----

----

--final v putval

(int hash, k key, v value,

boolean onlyifabsent,

boolean evict)

//說明找到的元素key一樣,進行替換,break跳出迴圈即可

if(e.hash == hash &&

((k = e.key)

== key ||

(key != null && key.

equals

(k))))

break

; p = e;}}

----

----

----

----

----

----

----

----

----

----

----

----

----

----

--//e不等於null,說明找到了乙個與你插入元素完全一致的,進行替換

if(e != null)}--

----

----

----

----

----

----

----

----

----

----

----

----

----

----

//modcount:表示雜湊表結構被修改次數,替換元素不算次數

++modcount;

//插入新元素,size自增,如果自增大於擴容閾值,則觸發擴容if(

++size > threshold)

resize()

;afternodeinsertion

(evict)

;return null;

}

public v get

(object key)

----

----

----

----

----

----

----

----

----

----

----

----

----

----

--final node

getnode

(object key)

while

((e = e.next)

!= null);}

}return null;

}

構造hash表時,如果不指明初始大小,預設大小為16(即node陣列大小16),如果node陣列中的元素達到(填充比*node.length)重新調整hashmap大小 變為原來2倍大小,擴容很耗時

首先有乙個每個元素都是鍊錶(可能表述不準確)的陣列,當新增乙個元素(key-value)時,就首先計算元素key的hash值,以此確定插入陣列中的位置,但是可能存在同一hash值的元素已經被放在陣列同一位置了,這時就新增到同一hash值的元素的後面,他們在陣列的同一位置,但是形成了鍊錶,同一各煉表上的hash值是相同的,所以說陣列存放的是鍊錶。而當鍊錶長度太長時,鍊錶就轉換為紅黑樹,這樣大大提高了查詢的效率。

當鍊表陣列的容量超過初始容量的0.75時,再雜湊將鍊錶陣列擴大2倍,把原鍊錶陣列的搬移到新的陣列中

HashMap底層原始碼分析

static final int default initial capacity 1 4 aka 16表示1向左移4位,2的4次方 static final int maximum capacity 1 30 hashmap陣列的最大容量 static final float default lo...

HashMap底層原始碼解析

目錄 一 分析hashmap的資料結構 1.使用陣列儲存,加快訪問速度 2.陣列中的鍊錶,解決hash衝突 3.使用紅黑樹優化鍊錶,防止大量hash衝突 二 hashmap主要原始碼解讀 三 總結 在看原始碼之前,了解一下它的資料結構和執行過程,才能更快更加有效率的讀懂原始碼。hashmap實際儲存...

HashMap底層原始碼剖析

陣列 單向鍊錶 紅黑樹 陣列 陣列每一項都是乙個鍊錶,其實就是陣列和鍊錶的結合體 單向鍊錶 當法神hash碰撞時,首先會找到陣列對應位置,然後1.8採用尾插入法 1.7採用頭插入法 形成乙個單項鍊表結構 紅黑樹 當陣列中每項的鍊錶長度大於8時,會轉換為紅黑樹 hash碰撞 不同的key可能會產生相同...