HashMap底層實現原理 擴容機制

2021-10-25 10:42:33 字數 4089 閱讀 2591

hashmap基於map介面實現,元素以鍵值對的方式儲存,並且允許使用null 建和null 值, 因為key不允許重複,因此只能有乙個鍵為null,另外hashmap不能保證放入元素的順序,它是無序的,和放入的順序並不能相同。

hashmap的容量,預設是16

/**

* the default initial capacity - must be a power of two.

*/static final int default_initial_capacity=1

<<4;

// aka 16

hashmap的載入因子,預設是0.75

/**

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

*/static final float default_load_factor

=0.75f;

當hashmap中元素數超過容量*載入因子時,hashmap會進行擴容。

hashmap本質是乙個一定長度的陣列,陣列中存放的是鍊錶。

hashmap類中的元素是node類,翻譯過來就是節點,是定義在hashmap中的乙個內部類,實現了map.entry介面。

node類定義的原始碼:

static

class

node

v>

implements

map.entry

v>

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;}

}

node類的基本屬性有:

hash:key的雜湊值

key:節點的key,型別和定義hashmap時的key相同

value:節點的value,型別和定義hashmap時的value相同

所以node可以變成鍊錶,但不是雙向鍊錶,裡面有乙個hash的int值,這個值是現算得(高位取反,計算後去低位異或),它和key有關,但是不是key的hashcode值

由node節點組成鍊錶之後,hashmap定義了乙個node陣列:table

transient node table;
我們通過put方法來看往乙個空的hashmap裡放乙個值得時候會發生什麼。

1.當使用者呼叫put(k,v)方法,物件執行該方法。

我們進去put方法的原始碼

public

vput

(k key,

v value)

/** * implements map.put and related methods

** @param hash hash for key //剛才算的值

* @param key the key

* @param value the value to put

* @param onlyifabsent if true, don't change existing value //如果存在,則不改變它的值

* @param evict if false, the table is in creation mode. //如果不存在,去放值

* @return previous value, or null if none

*/

2.物件執行putval方法
final v

putval

(int hash,

k key,

v value, boolean onlyifabsent,

boolean evict)

threshold = newthr;

@suppresswarnings()

nodev>

newtab =

(nodev>

)new

node

[newcap]

;//建立乙個長度為16的陣列

table = newtab;

...return newtab;

table初始化完成後,putval依次放值

++modcount;if(

++size > threshold)

resize()

;afternodeinsertion

(evict)

;return

null

;

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;}}

if(e !=

null)}

++modcount;if(

++size > threshold)

//注釋5

resize()

;afternodeinsertion

(evict)

;return

null;}

}}

**解析:

1,注釋1,table對應位置無節點,則建立新的node節點放入對應位置。

2,注釋2,table對應位置有節點,如果hash值匹配,則替換。

3,注釋3,table對應位置有節點,如果table對應位置已經是乙個treenode,不再是node,也就說,table對應位置是treenode,表示已經從鍊錶轉換成了紅黑樹,則執行插入紅黑樹節點的邏輯。

4,注釋4,table對應位置有節點,且節點是node(鍊錶狀態,不是紅黑樹),鍊錶中節點數量大於treeify_threshold,則考慮變為紅黑樹。實際上不一定真的立刻就變,table短的時候擴容一下也能解決問題,後面的**會提到。

5,注釋5,hashmap中節點個數大於threshold,會進行擴容

第二次擴容

final nodev>

resize()

else

}while

((e = next)

!=null);

if(lotail !=

null)if

(hitail !=

null)}

}}}return newtab;

第二次擴容完成

首先建立hashmap的時候,底層陣列還沒有初始化,它會去檢查當前的table,如果table為空,會去拿到預設的大小(16)和載入因子(12),建立長度為16的陣列。以node為節點,put方法的key轉為hash(高反低異),節點的hash值和當前長度-1進行與運算,也就是對16取模,得到當前值應該被防止的位置。如果這個位置已經由值存在,則被放置到已經存在的值之後(鍊錶)。

當一直存放到第13個值得時候(第12個值不擴容),呼叫resize方法 長度擴容到32,載入因子為24 。

原來的值可能形成鍊錶,鍊錶之前的值是對16取模,比如在3這個節點上,現在要對32取模,那麼就有可能在兩個節點上,要麼在3上,要麼在19上 所以求需要將鍊錶上的值都拿出來,來確定是在3這個節點上還是19節點上,判斷完成後,有乙個lohead(低位)和hihead(高位),兩個都形成了乙個新的鍊錶,於是將lohead的值儲存到原來的位置上, hihead的值將被放到19的位置上

hashmap底層實現原理

每次初始化hashmap都會構造乙個table陣列,而table陣列的元素為entry節點。static class entryimplements map.entryhashmap也可以說是乙個陣列鍊錶,hashmap裡面有乙個非常重要的內部靜態類 entry,這個entry非常重要,它裡面包含了...

HashMap底層實現原理

hashmap map new hashmap 在例項化以後,底層建立了長度為16的一維陣列entry table 已經執行過put操作.map.put key1 value1 呼叫key1所在類的hashcode 計算key1雜湊值,此雜湊值經過某種演算法計算後,得到在entry陣列中的存放位置 ...

HashMap底層實現原理

一 jdk1.7中hashmap的底層實現原理 首先,當我們通過hashmap的構造方法建立乙個hashmap物件時,底層就會建立乙個entry型別的一維陣列 預設初始化長度為16 當我們執行put操作的時候,會呼叫key所屬類的hashcode方法計算出key的hash值,然後將hash值通過雜湊...