Java源碼解析HashMap的resize函數(shù)
HashMap的resize函數(shù),用于對(duì)HashMap初始化或者擴(kuò)容。
首先看一下該函數(shù)的注釋,如下圖。從注釋中可以看到,該函數(shù)的作用是初始化或者使table的size翻倍。如果table是null,那么就申請(qǐng)空間進(jìn)行初始化。否則,因?yàn)槲覀冊(cè)谑褂?的指數(shù)的擴(kuò)張,在原來table的每個(gè)位置的元素,在新的table中,他們要么待在原來的位置,要么移動(dòng)2的指數(shù)的偏移。從這里可以看出,擴(kuò)容前table每個(gè)位置上如果有多個(gè)元素,元素之間組成鏈表時(shí),在擴(kuò)容后,該鏈表中的元素,有一部分會(huì)待在原地,剩下的元素會(huì)往后移動(dòng)2的指數(shù)的偏移。
/** * Initializes or doubles table size. If null, allocates in * accord with initial capacity target held in field threshold. * Otherwise, because we are using power-of-two expansion, the * elements from each bin must either stay at same index, or move * with a power of two offset in the new table. * @return the table **/
接下來看一下resize的代碼,如下
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
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;
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
擴(kuò)容的過程分為兩部分,第一部分是對(duì)threshold和table的初始化或者重新計(jì)算,第二部分是對(duì)HashMap中的元素進(jìn)行重新放置。初始化的過程比較簡(jiǎn)單,基本就是使用默認(rèn)值,初始化HashMap的各個(gè)成員變量。重新計(jì)算時(shí),是會(huì)申請(qǐng)一個(gè)2倍大小的Node數(shù)組,用作的新的HashMap的存儲(chǔ)空間。
之后的過程是,對(duì)原來HashMap中的每一個(gè)位置進(jìn)行遍歷,把該位置上的各個(gè)元素重新放置到新的table中。所以在循環(huán)的過程中,會(huì)定義loHead,loTail,hiHead,hiTail,分別表示留著原地的鏈表的頭和尾,移動(dòng)到更高位置的鏈表的頭和尾。這里需要注意一點(diǎn),在jdk1.8中,擴(kuò)容后鏈表中元素的順序和擴(kuò)容前鏈表中元素的位置,是相同的,并不會(huì)像jdk1.7那樣會(huì)發(fā)生逆序。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
相關(guān)文章
詳解 maven的pom.xml用<exclusion>解決版本問題
這篇文章主要介紹了詳解 maven的pom.xml用<exclusion>解決版本問題的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-09-09
快速學(xué)習(xí)JavaWeb中監(jiān)聽器(Listener)的使用方法
這篇文章主要幫助大家快速學(xué)習(xí)JavaWeb中監(jiān)聽器(Listener)的使用方法,感興趣的小伙伴們可以參考一下2016-09-09
Spring Boot2解決idea console 控制臺(tái)輸出亂碼的問題
這篇文章主要介紹了Spring Boot2解決idea console 控制臺(tái)輸出亂碼的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
關(guān)于TreeMap自定義排序規(guī)則的兩種方式
這篇文章主要介紹了關(guān)于TreeMap自定義排序規(guī)則的兩種方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
java鎖機(jī)制ReentrantLock源碼實(shí)例分析
這篇文章主要為大家介紹了java鎖機(jī)制ReentrantLock源碼實(shí)例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
SpringCloud Config分布式配置中心使用教程介紹
springcloud config是一個(gè)解決分布式系統(tǒng)的配置管理方案。它包含了 client和server兩個(gè)部分,server端提供配置文件的存儲(chǔ)、以接口的形式將配置文件的內(nèi)容提供出去,client端通過接口獲取數(shù)據(jù)、并依據(jù)此數(shù)據(jù)初始化自己的應(yīng)用2022-12-12

