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的容量。
所以負載因子越大則散列表的裝填程度越高,也就是能容納更多的元素,元素多了,鏈表大了,所以此時索引效率就會降低。
反之,負載因子越小則鏈表中的數據量就越稀疏,此時會對空間造成浪費,但是此時索引效率高。
