欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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值計(jì)算出的數(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)文章

  • Redis緩存策略超詳細(xì)講解

    Redis緩存策略超詳細(xì)講解

    實(shí)際開發(fā)中緩存處理是必須的,不可能我們每次客戶端去請求一次服務(wù)器,服務(wù)器每次都要去數(shù)據(jù)庫中進(jìn)行查找,為什么要使用緩存?說到底是為了提高系統(tǒng)的運(yùn)行速度
    2022-09-09
  • btrace定位生產(chǎn)故障的方法示例

    btrace定位生產(chǎn)故障的方法示例

    這篇文章主要介紹了btrace定位生產(chǎn)故障的方法示例,文中通過示例代碼介紹的很詳細(xì),相信對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。
    2017-02-02
  • Java的Dialog和FileDialog你知道啊

    Java的Dialog和FileDialog你知道啊

    這篇文章主要為大家詳細(xì)介紹了Java的Dialog和FileDialog,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • 用Java實(shí)現(xiàn)OCR功能揭秘

    用Java實(shí)現(xiàn)OCR功能揭秘

    想知道如何用Java實(shí)現(xiàn)OCR功能嗎?本指南將揭秘這一神秘技術(shù),讓你輕松掌握OCR的實(shí)現(xiàn)方法,無論是想提升技能還是解決問題,這篇指南都能幫助你一臂之力,需要的朋友可以參考下
    2023-12-12
  • Spring?Boot集成validation實(shí)現(xiàn)參數(shù)校驗(yàn)功能

    Spring?Boot集成validation實(shí)現(xiàn)參數(shù)校驗(yàn)功能

    Bean?Validation?是一個運(yùn)行時的數(shù)據(jù)驗(yàn)證框架,在驗(yàn)證之后驗(yàn)證的錯誤信息會被馬上返回,這篇文章主要介紹了Spring?Boot集成validation實(shí)現(xiàn)參數(shù)校驗(yàn)功能,需要的朋友可以參考下
    2024-05-05
  • Java聊天室之解決連接超時問題

    Java聊天室之解決連接超時問題

    這篇文章主要為大家詳細(xì)介紹了Java簡易聊天室之解決連接超時問題的方法,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,需要的可以了解一下
    2022-10-10
  • MybatisPlus條件查詢的具體使用

    MybatisPlus條件查詢的具體使用

    MybatisPlus通過條件構(gòu)造器可以組裝復(fù)雜的查詢條件,本文主要介紹了MybatisPlus條件查詢的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Java利用trueLicense實(shí)現(xiàn)項(xiàng)目離線證書授權(quán)操作步驟

    Java利用trueLicense實(shí)現(xiàn)項(xiàng)目離線證書授權(quán)操作步驟

    文章介紹了如何使用trueLicense實(shí)現(xiàn)離線授權(quán)控制,包括生成公私鑰、創(chuàng)建證書校驗(yàn)?zāi)K、生成證書模塊和測試模塊,通過這種方式,可以控制用戶使用的項(xiàng)目模塊、授權(quán)周期、使用的設(shè)備和服務(wù)器,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • Spring MVC攔截器的基本使用方法

    Spring MVC攔截器的基本使用方法

    這篇文章主要給大家介紹了關(guān)于Spring MVC攔截器的基本使用方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Spring MVC具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • Kibana的安裝和配置全過程

    Kibana的安裝和配置全過程

    Kibana是一個開源的數(shù)據(jù)分析和可視化平臺,它與Elasticsearch緊密集成,提供了一個直觀的Web界面,使您可以快速地搜索、分析和可視化數(shù)據(jù),在本文中,我們將介紹如何安裝和配置Kibana
    2024-12-12

最新評論