Java基礎-HashMap

1.結構(JDK1.7)

在這裏插入圖片描述
HashMap底層主要代碼:

transient Entry[] table;  

從代碼中可以看到一個hashmap的主幹就是一個數組結構,當新建一個hashmap的時候,就會初始化一個數組。

static class Entry<K,V> implements Map.Entry<K,V> {  
        final K key;  
        V value;  
        final int hash;  
        Entry<K,V> next;  
..........  
}  

Entry就是數組中的元素,它持有一個指向下一個元素的引用,這就構成了鏈表。
往hashmap中put元素的時候,先根據key的hash值得到這個元素在數組中的位置(即下標),然後就可以把這個元素放到對應的位置中了。如果這個元素所在的位子上已經存放有其他元素了,那麼在同一個位子上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。從hashmap中get元素時,首先計算key的hashcode,找到數組中對應位置的某一元素,然後通過key的equals方法在對應位置的鏈表中找到需要的元素。從這裏我們可以想象得到,如果每個位置上的鏈表只有一個元素,那麼hashmap的get效率將是最高的

2.擴容機制

2.1變量:
  • Node<K,V>:鏈表節點,包含了key、value、hash、next指針四個元素
  • table:Node<K,V>類型的數組,裏面的元素是鏈表,用於存放HashMap元素的實體,即容量,默認16。
  • size:記錄了放入HashMap的元素個數
  • loadFactor:負載因子,默認是0.75
  • threshold:擴容的閾值,決定了HashMap何時擴容,以及擴容後的大小,一般等於,等於 table * loadFactor,默認12。當元素數量超過閾值時便會觸發擴容。
2.2擴容時間:

HashMap使用的是懶加載,構造完HashMap對象後,只要不進行put 方法插入元素之前,HashMap並不會去初始化或者擴容table。
當首次調用put方法時,HashMap會發現table爲空然後調用resize方法進行初始化,當添加完元素後,如果HashMap發現size(元素總數)大於threshold(閾值),則會調用resize方法進行擴容

2.3JDK7擴容機制:
  • 空參數的構造函數:以默認容量、默認負載因子、默認閾值初始化數組。內部數組是空數組。
  • 有參構造函數:根據參數確定容量、負載因子、閾值等。
  • 第一次put時會初始化數組,其容量變爲不小於指定容量的2的冪數。然後根據負載因子確定閾值。
  • 如果不是第一次擴容,則 新容量 = 舊容量 * 2;新閾值 = 新容量 * 負載因子
2.4JDK8擴容機制:
  • 空參數的構造函數:實例化的HashMap默認內部數組是null,即沒有實例化。第一次調用put方法時,則會開始第一次初始化擴容,長度爲16。
  • 有參構造函數:用於指定容量。會根據指定的正整數找到不小於指定容量的2的冪數,將這個數設置賦值給閾值(threshold)。第一次調用put方法時,會將閾值賦值給容量,然後讓 閾值 = 容量 * 負載因子。(因此並不是我們手動指定了容量就一定不會觸發擴容,超過閾值後一樣會擴容)
  • 如果不是第一次擴容,則容量變爲原來的2倍,閾值也變爲原來的2倍。(容量和閾值都變爲原來的2倍時,負載因子還是不變)
  • 首次put時,先會觸發擴容(算是初始化),然後存入數據,然後判斷是否需要擴容
  • 不是首次put,則不再初始化,直接存入數據,然後判斷是否需要擴容
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章