前言
本文是基於Java 8
的HashMap
進行分析,主要是介紹HashMap
中的成員變量和類變量的用途,以及分析HashMap
的數據結構。
變量分析
在HashMap
中存在多個成員變量和類變量,搞清楚它們的用途有助於我們更深入瞭解HashMap
,下面是它們的介紹:
/**
* 默認的初始容量,必須爲2的次冪
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 總所周知是16
/**
* 最大容量
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 默認的負載因子
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* 將鏈表轉化爲紅黑樹的閾值,當鏈表節點數大於或等於該閾值-1則轉化爲紅黑樹
*/
static final int TREEIFY_THRESHOLD = 8;
/**
* 將紅黑樹轉化爲鏈表的閾值,當紅黑樹的節點小於該閾值時轉化爲鏈表
*/
static final int UNTREEIFY_THRESHOLD = 6;
/**
* 允許進行鏈表轉化爲紅黑樹的閾值,只有散列表大小大於或等於該值才能進行紅黑樹轉化
*/
static final int MIN_TREEIFY_CAPACITY = 64;
/**
* HashMap中存儲數據的數組,也稱爲散列表。
* 建議保持長度爲2的次冪
*/
transient Node<K,V>[] table;
/**
* 緩存entrySet()方法的值
*/
transient Set<Map.Entry<K,V>> entrySet;
/**
* Map中鍵值對的個數
*/
transient int size;
/**
* HashMap數據結構被改變的次數,一般是指散列表的長度改變、Node鏈表增加或者減少節點
* 這個參數是用於快速失敗機制
*/
transient int modCount;
/**
* 下一次觸發調整大小(resize()方法)的閾值,一般爲容量乘以負載因子
*/
int threshold;
/**
* 散列表的負載因子,用於計算擴容的閾值
*/
final float loadFactor;
數據結構
HashMap
使用拉鍊法解決哈希表中存在的哈希衝突問題,所以HashMap
底層是用以Node
組成的鏈表爲元素的數組table
來存儲鍵值對,每個Node
就是一個鍵值對對象。table
稱呼爲散列表。
而table
對應的是散列表,是因爲無論是存儲還是讀取鍵值對的時候,都會對key
進行hash%table.length
運算來進行散列表的命中,然後操作命中的索引對應的Node
鏈表(還是會比較key
和hash
)。
以上爲Java 8
之前版本的HashMap
的實現,而Java 8
進行了優化:就是當鏈表節點數超過閾值TREEIFY_THRESHOLD(8)
時,則會將鏈表轉化爲紅黑樹。
如果只是使用文字描述的話會很難理解,所以下面會通過一幅圖展示: