因為最近想面試,所以複習下。分析學習基於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的...