HashMap底層實現原理


HashMap在底層數據結構

采用了數組+鏈表+紅黑樹,(內部實現是一個桶數組,每個桶中存放着一個單鏈表的頭結點,當鏈表長度大於8的時候轉換為紅黑樹。)

通過散列映射來存儲鍵值對數據因為在查詢上使用散列碼(通過鍵生成一個數字作為數組下標,這個數字就是hash code)

所以在查詢上的訪問速度比較快,HashMap最多允許一對鍵值對的Key為Null,允許多對鍵值對的value為Null。它是非線程安全的。在排序上面是無序的。

HashMap的主要成員變量:

transient Node<K,V>[] table:這是一個Node類型的數組(也有稱作Hash桶),可以從下面源碼中看到靜態內部類Node在這邊可以看做就是一個節點,多個Node節點構成鏈表,當鏈表長度大於8的時候轉換為紅黑樹。

transient int size:表示當前HashMap包含的鍵值對數量

transient int modCount:表示當前HashMap修改次數

int threshold:表示當前HashMap能夠承受的最多的鍵值對數量,一旦超過這個數量HashMap就會進行擴容

final float loadFactor:負載因子,用於擴容

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4:默認的table初始容量

static final float DEFAULT_LOAD_FACTOR = 0.75f:默認的負載因子


擴容機制核心方法Node<K,V>[] resize():
 HashMap擴容可以分為三種情況:

第一種:使用默認構造方法初始化HashMap。從前文可以知道HashMap在一開始初始化的時候會返回一個空的table,並且thershold為0。因此第一次擴容的容量為默認值DEFAULT_INITIAL_CAPACITY也就是16。同時threshold = DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR = 12。

第二種:指定初始容量的構造方法初始化HashMap。那么從下面源碼可以看到初始容量會等於threshold,接着threshold = 當前的容量(threshold) * DEFAULT_LOAD_FACTOR。

第三種:HashMap不是第一次擴容。如果HashMap已經擴容過的話,那么每次table的容量以及threshold量為原有的兩倍。
這邊也可以引申到一個問題就是HashMap是先插入數據再進行擴容的,但是如果是剛剛初始化容器的時候是先擴容再插入數據。

負載因子為什么會影響HashMap性能

我們都知道有序數組存儲數據,對數據的索引效率都很高,但是插入和刪除就會有性能瓶頸(回憶ArrayList),

鏈表存儲數據,要一次比較元素來檢索出數據,所以索引效率低,但是插入和刪除效率高(回憶LinkedList),

兩者取長補短就產生了哈希散列這種存儲方式,也就是HashMap的存儲邏輯.

負載因子表示一個散列表的空間的使用程度,有這樣一個公式:initailCapacity*loadFactor=HashMap的容量。

所以負載因子越大則散列表的裝填程度越高,也就是能容納更多的元素,元素多了,鏈表大了,所以此時索引效率就會降低。

反之,負載因子越小則鏈表中的數據量就越稀疏,此時會對空間造成浪費,但是此時索引效率高。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM