基礎知識 一 HashMap 原始碼詳解

2021-07-28 15:55:21 字數 4056 閱讀 9704

因為最近想面試,所以複習下。分析學習基於jdk1.8

hashmap 繼承於 abstrackhashmap 實現於 map, cloneable, serializable,內部使用雜湊鍊錶 紅黑樹實現。注意此map不是執行緒安全的,如果需要同步使用請使用concurrenthashmap 或者 collections.synchronizedmap

常量引數

1、下面的都是直接static final 的值,也就是在jvm準備的時候就已經初始化了

default_initial_capacity =16 預設容量為

maximum_capacity =1 << 30 最大容量為

default_load_factor = 0.75f 預設負載因子

treeify_threshold=8 鍊錶轉換紅黑樹的閥值

untreeify_threshold=6 紅黑樹轉換鍊錶的閥值

min_treeify_capacity=64 桶中bin最小hash容量,如果大於這個值會進行resize擴容操作,此值至少是treeify_threshold的4倍

2、下面說下成員變數 都是 transient,也就是說不會被序列化的字段

node table  hashmap內部類實現了map的內部類entry,用於儲存k,v,第一次使用的時候被建立,根據需要可以進行resize。分配長度為2的冥次方

set> entryset   當被呼叫entryset時被賦值。通過keyset()方法可以得到map key的集合,通過values方法可以得到map value的集合

int size 存放在map中k,v的總數

int modcount  hashmap被結構性修改的次數。(結構性修改是指改變了kv對映數量的操作或者修改了hashmap的內部結構(如 rehash)。這個用於fail-fast

int threshold  進行resize的閥值,當map中k,v數量(size) 超過了這個值,那將進行resize操作。

threshold  =default_initial_capacity*default_load_factor

final float loadfactor 負載因子

構造方法

目前有4個構造方法

1、public hashmap(int initialcapacity, float loadfactor)

引數為初始容量,負載因子

步驟:1、如果容量引數小於0就丟擲異常

2、如果容量引數大於最大值maximum_capacity 就初始化為maximum_capacity

3、如果負載因子小於等於0或者是乙個非數字就丟擲異常

4、賦值負載因子

5、使用tablesizefor 計算初始容量

方法原始碼解析

先看put方法,使用的是

public

v put(k

key, v

value

) 內建final方法,不可被子類重寫,在編譯期已經靜態繫結

final

vputval

(int

hash

, kkey

, vvalue

,boolean

onlyifabsent

,boolean

evict

) 引數:

hash 計算出的hash值

key  傳入鍵

value 傳入值

onlyifabsent 預設false,為true的時候不覆蓋已存在的值

evict 預設true

transient node table;

static final int treeify_threshold = 8;

transient int modcount;

transient int size;

int threshold;

//新手看到這麼多變數肯定暈了,記住一點,這是引用傳遞

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

boolean evict)

//判斷當前index的元素是否一樣,一樣就賦值替換,跳出

if (e.hash == hash &&

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

break;

p = e;}}

////將老元素的value提取出

v oldvalue = e.value;

//判斷是否覆蓋老元素的值

if (!onlyifabsent || oldvalue == null)

e.value = value;

//這個方法是給linkedhashmap留得,因為他用的也是這個put方法

afternodeaccess(e);

return oldvalue;}}

//更新結構更改次數

++modcount;

//判斷+1後的size是否大於閥值預設計算出的是12)

if (++size > threshold)

resize();

//這個方法是給linkedhashmap留得,因為他用的也是這個put方法

afternodeinsertion(evict);

return null;

}

下面說下resize

int threshold;

static final int maximum_capacity = 1 << 30;

static final int default_initial_capacity = 1 << 4; // aka 16

static final float default_load_factor = 0.75f;

final float loadfactor;

// 擴容方法,不能被重寫

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;

// 走到這代表是個新map首次建立

else

if (newthr == 0)

threshold = newthr;

@suppresswarnings()

node newtab = new node[newcap];

// 賦值擴容完的node給teble

table = newtab;

// 判斷當前table是否為空,如果為null說明是新建,否則為擴容

if (oldtab != null) else

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

// 將鍊錶放到原位

if (lotail != null)

if (hitail != null) }}

}}

return newtab;

}

下面說下簡單的get

public v get(object key) 

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

return null;

}

hashMap基礎原始碼解析

2.hashmap基礎原始碼解析 鍊錶調整為紅黑樹的鍊錶長度閾值是什麼?紅黑樹調整為鍊錶的鍊錶長度閾值是什麼?鍊錶調整為紅黑樹的陣列最小閾值是什麼?hashmap的陣列table儲存的就是乙個個的node型別,很清晰地看到有一對鍵值,還有乙個指向next的指標 以下只擷取了部分原始碼 copysta...

HashMap原始碼解讀(一)

在我們面試過程中,經常會遇到要求說hashmap的底層實現,在jdk原始碼中,oracle公司給出了我們hashmap的原始碼,通過閱讀hashmap的原始碼,我們可以很清楚的知道hashmap是怎麼實現的。下面我們開始閱讀hashmap的原始碼吧。public class hashmap exte...

HashMap原始碼分析 一

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