最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java的HashMap源碼解析

 更新時間:2023年11月15日 10:11:55   作者:龍三丶  
這篇文章主要介紹了Java的HashMap源碼解析,HashMap是一個用于存儲Key-Value鍵值對的集合,每一個鍵值對是一個Node,后臺是用一個Node數(shù)組來存放數(shù)據(jù),這個Node數(shù)組就是HashMap的主干,需要的朋友可以參考下

前言

以jdk1.8為例,HashMap是一個用于存儲Key-Value鍵值對的集合,每一個鍵值對是一個Node(jdk1.7叫做Entry)。后臺是用一個Node數(shù)組來存放數(shù)據(jù),這個Node數(shù)組就是HashMap的主干。

這里我們主要來分析HashMap的get和put方法。

put

public V put(K key, V value) {
	    	return putVal(hash(key), key, value, false, true);
	}
 
	final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
				   boolean evict) {
		Node<K,V>[] tab; Node<K,V> p; int n, i;
		//如果是第一次put,就進(jìn)行數(shù)組的大小初始化,默認(rèn)是16
		if ((tab = table) == null || (n = tab.length) == 0)
			n = (tab = resize()).length;
		//根據(jù)hash值,找到在數(shù)組中的位置,如果此位置沒有值,就new一個新的node插入
		if ((p = tab[i = (n - 1) & hash]) == null)
			tab[i] = newNode(hash, key, value, null);
		//如果數(shù)組該位置有值
		else {
			Node<K,V> e; K k;
			//判斷該位置節(jié)點(diǎn)的key是否和即將插入的key相等,相等就取出來等待覆蓋
			if (p.hash == hash &&
					((k = p.key) == key || (key != null && key.equals(k))))
				e = p;
			//若果該節(jié)點(diǎn)是紅黑樹,則調(diào)用紅黑樹相關(guān)方法
			else if (p instanceof TreeNode)
				e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
			//到了這里,說明該節(jié)點(diǎn)是鏈表,調(diào)用鏈表相關(guān)方法
			else {
				for (int binCount = 0; ; ++binCount) {
					//循環(huán)到最后一個節(jié)點(diǎn),然后插入新節(jié)點(diǎn)(1.7是往頭結(jié)點(diǎn)插入,1.8是往尾部插入)
					if ((e = p.next) == null) {
						p.next = newNode(hash, key, value, null);
						//判斷插入后的該鏈表的長度,如果大于8,就轉(zhuǎn)成紅黑樹
						if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
							treeifyBin(tab, hash);
						break;
					}
					//這里表示鏈表中某個節(jié)點(diǎn)的key與即將插入的key相等,就跳出循環(huán)等待覆蓋
					if (e.hash == hash &&
							((k = e.key) == key || (key != null && key.equals(k))))
						break;
					p = e;
				}
			}
			//這里表示有節(jié)點(diǎn)的key與新的key相等,那么就覆蓋
			if (e != null) {
				V oldValue = e.value;
				if (!onlyIfAbsent || oldValue == null)
					e.value = value;
				afterNodeAccess(e);
				return oldValue;
			}
		}
		++modCount;
		//插入完之后,如果導(dǎo)致size超過了預(yù)設(shè)的閾值,就進(jìn)行擴(kuò)容(1.7是插入前判斷,1.8是插入后判斷)
		if (++size > threshold)
			resize();
		afterNodeInsertion(evict);
		return null;
	}

擴(kuò)容步驟:

1、創(chuàng)建一個原數(shù)組兩倍大小的新數(shù)組,并且把閾值擴(kuò)大一倍。

2、遍歷原數(shù)組,進(jìn)行數(shù)據(jù)遷移。分為紅黑樹和鏈表兩種情況。

 好了,擴(kuò)容部分就不展開代碼詳細(xì)說明,接下來進(jìn)入get方法,相較于put方法就沒那么復(fù)雜了,且代碼量也比較少

get

public V get(Object key) {
		Node<K,V> e;
		return (e = getNode(hash(key), key)) == null ? null : e.value;
	}
	final Node<K,V> getNode(int hash, Object key) {
		Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
		//判斷底層node數(shù)組是否為空及該hash值對應(yīng)的數(shù)組位置是否有值
		if ((tab = table) != null && (n = tab.length) > 0 &&
				(first = tab[(n - 1) & hash]) != null) {
			//判斷該數(shù)組的節(jié)點(diǎn)是不是我們需要的值,是就直接返回
			if (first.hash == hash &&
					((k = first.key) == key || (key != null && key.equals(k))))
				return first;
			if ((e = first.next) != null) {
				//該節(jié)點(diǎn)是紅黑樹則直接調(diào)用紅黑樹的遍歷方法
				if (first instanceof TreeNode)
					return ((TreeNode<K,V>)first).getTreeNode(hash, key);
				//遍歷鏈表
				do {
					if (e.hash == hash &&
							((k = e.key) == key || (key != null && key.equals(k))))
						//是我們需要的值,返回
						return e;
				} while ((e = e.next) != null);
			}
		}
		return null;
	}

注意:

1、HashMap底層就是用一個個的Node來存儲單個數(shù)據(jù),每個Node有hash值、key、value、及指向下一個Node的引用(next)。Node數(shù)組中就是所有鏈表的頭節(jié)點(diǎn)。

2、當(dāng)出現(xiàn)hash沖突的情況,原Node的next就會指向新插入的Node,也就是形成了鏈表。

3、每次擴(kuò)容的長度必須是2的冪,因?yàn)?,根?jù)key的hash值計算出的數(shù)組索引應(yīng)盡量不要重復(fù),實(shí)現(xiàn)均勻分布,均勻分布的話大部分查找的數(shù)據(jù)都是以數(shù)組的形式查找,就不會蛻變成鏈表,而數(shù)組的查找效率比鏈表高很多。

4、影響擴(kuò)容的因素有兩個:數(shù)組的長度(DEFAULT_INITIAL_CAPACITY)和負(fù)載因子(DEFAULT_LOAD_FACTOR),當(dāng)這兩個相乘大于等于當(dāng)前HashMap的Size時,就進(jìn)行擴(kuò)容

5、擴(kuò)容在并發(fā)情況下可能會形成鏈表環(huán),存在并發(fā)安全問題,這點(diǎn)需要注意

6、當(dāng)鏈表的節(jié)點(diǎn)超過8個時,會轉(zhuǎn)成紅黑樹,鏈表的時間復(fù)雜度為O(n),而紅黑樹為O(logn)

到此這篇關(guān)于Java的HashMap源碼解析的文章就介紹到這了,更多相關(guān)HashMap源碼 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SSM框架+Plupload實(shí)現(xiàn)分塊上傳大文件示例

    SSM框架+Plupload實(shí)現(xiàn)分塊上傳大文件示例

    這篇文章主要介紹了SSM框架+Plupload實(shí)現(xiàn)分塊上傳示例(Spring+SpringMVC+MyBatis+Plupload),將用戶選中的文件(可多個)分隔成一個個小塊,依次向服務(wù)器上傳,有興趣的可以了解一下。
    2017-03-03
  • Springboot項(xiàng)目啟動成功后可通過五種方式繼續(xù)執(zhí)行

    Springboot項(xiàng)目啟動成功后可通過五種方式繼續(xù)執(zhí)行

    本文主要介紹了Springboot項(xiàng)目啟動成功后可通過五種方式繼續(xù)執(zhí)行,主要包括CommandLineRunner接口,ApplicationRunner接口,ApplicationListener接口,@PostConstruct注解,InitalizingBean接口,感興趣的可以了解一下
    2023-12-12
  • Java Eclipse中實(shí)現(xiàn)快速替換變量

    Java Eclipse中實(shí)現(xiàn)快速替換變量

    這篇文章主要介紹了Java Eclipse中實(shí)現(xiàn)快速替換變量,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Java http加簽、驗(yàn)簽實(shí)現(xiàn)方案詳解

    Java http加簽、驗(yàn)簽實(shí)現(xiàn)方案詳解

    這篇文章主要介紹了Java http加簽、驗(yàn)簽實(shí)現(xiàn)方案詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-07-07
  • default怎么修飾接口中的方法詳解

    default怎么修飾接口中的方法詳解

    今天給各位小伙伴們總結(jié)一下default怎么修飾接口中的方法,文中有非常詳細(xì)的圖文解說.對正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05
  • 解決mybatis中的mapper命名問題

    解決mybatis中的mapper命名問題

    這篇文章主要介紹了解決mybatis中的mapper命名問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 深入理解ContextClassLoader加載器

    深入理解ContextClassLoader加載器

    這篇文章主要介紹了深入理解ContextClassLoader加載器,Thread?context?class?loader存在的目的主要是為了解決parent?delegation機(jī)制下無法干凈的解決的問題,需要的朋友可以參考下
    2023-10-10
  • SpringBoot配置RocketMQ的詳細(xì)過程

    SpringBoot配置RocketMQ的詳細(xì)過程

    這篇文章主要介紹了SpringBoot配置RocketMQ的詳細(xì)過程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-03-03
  • SpringBoot熱部署設(shè)置方法詳解

    SpringBoot熱部署設(shè)置方法詳解

    在實(shí)際開發(fā)中,每次修改代碼就需要重啟項(xiàng)目,重新部署,對于一個后端開發(fā)者來說,重啟確實(shí)很難受。在java開發(fā)領(lǐng)域,熱部署一直是一個難以解決的問題,目前java虛擬機(jī)只能實(shí)現(xiàn)方法體的熱部署,對于整個類的結(jié)構(gòu)修改,仍然需要重啟項(xiàng)目
    2022-10-10
  • java使用OpenCV從視頻文件中獲取幀

    java使用OpenCV從視頻文件中獲取幀

    這篇文章主要為大家詳細(xì)介紹了java使用OpenCV從視頻文件中獲取幀,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07

最新評論

游戏| 防城港市| 迁西县| 长丰县| 清远市| 托里县| 海晏县| 白朗县| 太保市| 麻阳| 泾源县| 轮台县| 治多县| 麻阳| 霍邱县| 手机| 长兴县| 高邑县| 天水市| 昆明市| 九江市| 乐山市| 万山特区| 临朐县| 濮阳市| 六盘水市| 巴青县| 焉耆| 崇左市| 康马县| 绥德县| 碌曲县| 墨脱县| 来宾市| 新泰市| 罗田县| 高安市| 喜德县| 苍梧县| 长汀县| 林口县|