如何進(jìn)行HashMap的源碼剖析

如何進(jìn)行HashMap的部分源碼剖析,針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。

鞏義網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián),鞏義網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為鞏義上千余家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站制作要多少錢,請找那個(gè)售后服務(wù)好的鞏義做網(wǎng)站的公司定做!

HashMap基于哈希表的 Map 接口的實(shí)現(xiàn)。此實(shí)現(xiàn)提供所有可選的映射操作,并允許使用 null 值和 null 鍵。(除了不同步和允許使用 null 之外,HashMap 類與 Hashtable 大致相同。)此類不保證映射的順序,特別是它不保證該順序恒久不變。HashMap的結(jié)構(gòu)如下:

如何進(jìn)行HashMap的源碼剖析

我們可以看到HashMap的結(jié)構(gòu)主要分為兩大部分:左側(cè)的table和右側(cè)的鏈表,下面重點(diǎn)分析HashMap的源碼。

1.常量

如何進(jìn)行HashMap的源碼剖析

2.常用的構(gòu)造方法

如何進(jìn)行HashMap的源碼剖析

3.常用方法

(1)、final int hash(Object k),此方法用來計(jì)算key的哈希值,由方法最后的幾行可以看到,為了保證key的均勻散列,并沒有使用hashCode%length的方法,因?yàn)橐莆贿\(yùn)算符不僅可以更均勻的散列而且勻速速度也比hashCode%length更快。

如何進(jìn)行HashMap的源碼剖析

(2)、public V get(Object key)

如何進(jìn)行HashMap的源碼剖析

我們看到,get方法首先判斷key是否為null,如果為null,則調(diào)用getForNullKey(),否則調(diào)用getEntry(key)方法獲取value,讓我們來繼續(xù)分析getForNullKey的源碼:

private V getForNullKey() 

如何進(jìn)行HashMap的源碼剖析

可見:循環(huán)遍歷table[0]的那個(gè)鏈表,直到找到key==null的Entry,否則返回null;為什么是table[0]呢?因?yàn)樵趐ut的時(shí)候如果key==null,直接將entry存儲在table[0]的位置,我們在后面分析put方法。接下來再分析getEntry(key)方法:

如何進(jìn)行HashMap的源碼剖析

通過key的Hash值計(jì)算Entry所在table的小標(biāo),請注意計(jì)算下標(biāo)的方法通過indexFor()方法得到,然后遍歷Entry,直到找到hash和equals都相等的Entry后返回,否則返回null;

好了,get方法基本就是這樣,接下來我們一起來分析put方法。

(3)、 public V put(K key, V value)

如何進(jìn)行HashMap的源碼剖析

put方法的大致流程是:

①、首先判斷key是否為null,如果為null,調(diào)用putForNullKey(value)方法,請大家注意,putForNullKey和上面的getForNullKey的邏輯是一一對應(yīng)的哦。

②、計(jì)算key的Hash值,通過indexFor()方法定位到元素存儲在table的位置table[i]。

③、循環(huán)遍歷table[i],如果新值和舊值相等,覆蓋舊值后返回舊值

④、modCount++,操作次數(shù)+1,調(diào)用addEntry將新值插入到鏈表。

讓我們來分析putForNullKey(value)方法源碼:

如何進(jìn)行HashMap的源碼剖析

請看,這里又是table[0],和getForNullKey中的table[0]對稱,遍歷-->新值覆蓋舊值-->返回舊值-->操作數(shù)+1-->插入新元素,很容易理解。

接下來重點(diǎn)來了,讓我們來分析addEntry方法中的一系列邏輯:

如何進(jìn)行HashMap的源碼剖析

首先,threshold=capacity * load factor,也就是臨界值=容量*加載因子=16*0.75f, map中使用量超過threshold,會擴(kuò)容為原來的2倍。resize是一個(gè)非常復(fù)雜的過程,涉及到rehash等,后面我在介紹,現(xiàn)在咱們重點(diǎn)看addEntry()。bucketIndex是元素存儲在table的下標(biāo),也就是將元素存儲在table[bucketIndex]。最后調(diào)用createEntry將新元素存儲在HashMap中,createEntry的源碼如下:

如何進(jìn)行HashMap的源碼剖析

通過new Entry(hash,key,value,e),將新元素插到table[bucketIndex]中,我們來看Entry的構(gòu)造方法:

如何進(jìn)行HashMap的源碼剖析

重點(diǎn)在next = n這行,看到到插入元素到鏈表中使用的頭插法,不用尾插的目的估計(jì)是為了節(jié)省遍歷鏈表的開銷吧。

好了,put方法就是這樣,其實(shí)也特別好理解,接下來我們來分析Entry這類。

4.Entry內(nèi)部類

HashMap有一個(gè)變量:transient Entry<K,V>[] table,可以看到table是一個(gè)Entry的數(shù)組,并且Entry本身是一個(gè)鏈表的一個(gè)元素。Entry<K,V> implements Map.Entry<K,V>,而Map.Entry是一個(gè)接口。Entry包含四個(gè)元素,final K key; V value; Entry<K,V> next;int hash;hash是這個(gè)元素的hash值,其余的三個(gè)元素就不解釋了。Entry類的方法基本上都很簡單,大家可以通過閱讀源碼來理解,我重點(diǎn)解釋一下equals和hashCode這兩個(gè)方法,源碼如下:

如何進(jìn)行HashMap的源碼剖析比較連個(gè)Entry是否相等就是通過if中的條件,比較容易理解,hashCode源碼:

如何進(jìn)行HashMap的源碼剖析

最后,重點(diǎn)分析rehash方法,在分析rehash時(shí),我先解釋一下什么是rehash:當(dāng)我們的HashMap的使用量超過了threshold=capacity * load factor,也就是臨界值=容量*加載因子=16*0.75f,就會發(fā)生rehash,將容量擴(kuò)大為原來的兩倍,然后所有的元素根據(jù)新的hash規(guī)則重新散列到不同的table[i]中。但是rehash有很大的性能消耗,所以如果我們在使用HashMap時(shí)能預(yù)測到元素的個(gè)數(shù),最好在構(gòu)造時(shí)就指定HashMap的大小。rehash的源碼如下:

如何進(jìn)行HashMap的源碼剖析

Entry[] newTable = new Entry[newCapacity],常見一個(gè)新的table,很消耗內(nèi)存的?。?!前面容易理解,重點(diǎn)看transfer方法,這個(gè)方法才是將元素重新散列的方法,源碼如下:

如何進(jìn)行HashMap的源碼剖析

循環(huán)遍歷table(舊數(shù)組),計(jì)算出newTable的下標(biāo),將舊元素e存儲到newTable中,這里有一個(gè)細(xì)節(jié)要注意,在我講put方法時(shí)提到過,插入元素的方法時(shí)頭插法,就是新的元素被添加到鏈表的頭部,但我們通過transfer方法可分析出:在rehash的時(shí)候,之前在頭部的元素會先進(jìn)行rehash,在尾部的元素會最后rehash,所以當(dāng)rehash結(jié)束后,之前在頭部的元素會沉到尾部,之前在尾部的元素會上升到頭部。

關(guān)于如何進(jìn)行HashMap的部分源碼剖析問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。

本文題目:如何進(jìn)行HashMap的源碼剖析
本文路徑:http://muchs.cn/article30/jchcso.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營銷推廣、網(wǎng)站建設(shè)、微信小程序、企業(yè)網(wǎng)站制作、品牌網(wǎng)站建設(shè)網(wǎng)頁設(shè)計(jì)公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司