hashmap在1.8中是以數組+鏈表+紅黑樹的結構實現的,在數組中的存放位置是用hash屬性&長度-1 去尋址的(因爲長度是2的冪,加上尋址方式,方便擴容,擴容兩倍後數據不在原來位置就在原來位置X2的地方),允許key爲null,但是只能有一個;value可以null,不限個數。
hashmap無參構造初始化時啥沒有,只有put時纔會調用resize()纔會有長度,默認16
一接口
實現了
Map<K,V>, Cloneable, Serializable 接口
繼承
AbstractMap類
二 內部一些屬性
DEFAULT_INITIAL_CAPACITY 默認長度,16,2的冪,原因是爲了擴容(後面說),尋址碰撞
MAXIMUM_CAPACITY 最大長度,2^30=1 073 741 824
DEFAULT_LOAD_FACTOR = 0.75f; 負載因子
TREEIFY_THRESHOLD = 8; 鏈表向紅黑樹轉化的閥值
UNTREEIFY_THRESHOLD = 6;紅黑樹轉化成鏈表的閥值
Node<K,V>[] table; node的數組,存放具體的值,
threshold 負載數量,容量*負載因子
size 長度。數組裏放了多少個值
MIN_TREEIFY_CAPACITY=64 轉爲紅黑樹的時候最小長度
數組
size 記錄長度
modCount記錄操作數
還有靜態內部類Node,存儲數據,key,value,hash,next(鏈表,指向下一個數據)
hash(),
計算hash值,獲取key.hashCode()^(key.hashCode()>>>16)(異或操作,計算快,key 爲null返回0)
put() ,
1.首先判斷table是否已經初始化,否則調用resize(),進行初始化。
2.獲取key對應位置的值,null就實例化一個新的node放進去,如果不null,或取得數據判斷hash是否相等equals,是的話取得當前值,不是的話就要遍歷了,(簡單的說就是看看當前位置是不是沒有hash衝突,當前位置不是鏈表也不是紅黑樹)當前位置空就直接放進去;如果是紅黑樹,調用putTreeVal()方法;已經有值的話就是個鏈表,當前位置node.next賦值爲當前對象,並進行判斷鏈表長度達到8,轉化成紅黑樹;
3.判斷(++size > threshold),根據條件進行判斷是否需要擴容(2倍)
4.treeifyBin()
轉化紅黑樹的時候,table長度最少要到64
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize();
resize()
擴容,
1.初始擴容,默認16
2.已經是最大長度了,不在擴容。
3..長度沒達到最大長度,*2 也沒達到最大長度。擴容兩倍
擴容是指重新構造一個新的數組(兩倍原數組),將原數組遍歷重新分配到新數組裏,因爲是兩倍擴容,並且長度時2的冪,尋址時又是獲取node.hash&(容量-1),使得數據不在當前位置就在原位置的2倍的地方,減少移動。