1)hashmap底層資料結構在1.7之前是陣列+鍊錶而1.8之後是陣列+鍊錶+紅黑樹
2)三個變數:initcapacity(陣列初始容量)、loadfactory(載入因子)、thresold
3)三個過程:陣列擴容的過程(resize)、擴容後原陣列資料轉移到新資料結構的過程、陣列新增元素的過程(putval)
4)三個方法:resize();、tablesizefor()、hash()
5)兩個機靈:
key.hash % n == key.hash & n
if(key.hash & oldcap == 0)
6)乙個思想:要理解hashmap在盡力的做到把元素均勻的放到每個陣列中,盡力的減小hash衝突,所以在這一思想下去理解hashmap中hash()函式的實現和陣列擴容為什麼總是2的冪次方這兩個關鍵點
說明:這裡就不重點分析其實現的介面和繼承層次的作用了,重點分析下面hashmap裡的原始碼解析
1)理解資料結構
分析table的資料結構:
2)重要變數解釋
default_initial_capacity:陣列預設初始化長度,預設為16
maximum_capacity:陣列最大容量2^30
default_load_factor:陣列容量載入度,有關陣列容量是否要擴容;初始為0.75之後的動態loadfactory=size/capacity(即hashmap的所有容量/陣列的容量),注意loadfactory其實就是hashmap在對空間和時間的平衡因子,過大,空間利用高了但時間上消耗多了;過小,時間消耗小了但空間利用少了。所以0.75就是乙個平衡
treeify_threshold:當鍊表的節點數大於該值,即8時煉表會自動轉為紅黑樹
untreeify_threshold:當紅黑樹的節點數小於該值6時會轉為鍊錶
min_treeify_capacity:鍊錶轉為紅黑樹時還要求陣列的長度不能小於該值64
thresold:衡量陣列長度是否要擴容了,thresold=loadfactory*capacity <= size時就要擴容了
3)重要方法講解
//hash方法講解
static final int hash(object key)
//該方法是將cap乙個可能不是2的冪次方的數,返回乙個最接近該數的乙個2的冪次方的數
static final int tablesizefor(int cap)
//resize方法包含了陣列怎麼擴容和陣列擴容後原始資料怎麼轉移
final node resize()
//如果老陣列的容量沒有達到最大,那麼就將容量擴容為原來的2倍同時增大thresold
為原來的2倍
else if ((newcap = oldcap << 1) < maximum_capacity &&
oldcap >= default_initial_capacity)
newthr = oldthr << 1; // double threshold
}//如果老陣列長度不大於0但oldthr大於0
else if (oldthr > 0) // initial capacity was placed in threshold
newcap = oldthr;
else
if (newthr == 0)
threshold = newthr;
@suppresswarnings()
node newtab = (node)new node[newcap];//這裡才真的建立好新的陣列
table = newtab;
//開始轉移原陣列裡的資料
if (oldtab != null)
else
} while ((e = next) != null);
if (lotail != null)
if (hitail != null) }}
}}return newtab;
}
說明:resize()方法比較重要,重點理解如何擴容和老資料到新陣列裡的下標是怎麼轉換的
//說明:該方法是put底層呼叫的方法也很重要,要理解整個過程
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)//加入元素後判斷陣列是否要擴容
resize();
afternodeinsertion(evict);
return null;
}
說明:putval的過程如下:
1、判斷陣列是否初始化,沒有就初始化
2、判斷帶插入的位置是否存在元素,沒有就直接插入,存在分三種情況
1)是紅黑樹的節點:那麼就按紅黑樹的規則插入
2)是鍊錶的節點那麼就遍歷鍊錶把該元素插入到末尾或者替換鍊錶中與其key相同的元素
3)帶插入位置的元素的k和該元素相同,那麼就直接替換老值
4)判斷是否要擴容
1)總體把握hashmap的底層資料結構:陣列+鍊錶+紅黑樹
2)理解為什麼陣列的長度一直是2的冪次方和陣列擴容過程
3)掌握老資料如何確定新位置的過程
4)掌握resize()和putval()和thresold、loadfactory的作用
java集合相關原始碼分析
hashmap 原始碼分析 hashset 原始碼分析 arraylist 原始碼分析 concurrentmap 原始碼分析 2018 03 25 map 綜述 一 徹頭徹尾理解 hashmap map 綜述 二 徹頭徹尾理解 linkedhashmap map 綜述 三 徹頭徹尾理解 concu...
java集合 ArrayList原始碼分析
arraylist是一種基於陣列實現的集合類,也是平常經常使用到的集合。其特性歸納如下 特性值 是否順序儲存 順序是否可重複儲存 可以是否可儲存null 可以是否執行緒安全 非執行緒安全 屬性說明 elementdata arraylist是基於陣列實現的,這就是arraylist用於儲存 size...
Hash底層原始碼分析
hsah 雜湊將乙個任意長度通過某種 函式函式演算法 轉換成乙個固定值,通過hash出來的值,通過只定位到map,key value 基本原理。hashtable是基於map介面的實現。這個版本的實現提供了所有map操作的實現並且允許null值和null鍵 除了允許空值 null 和不支援同步,ha...