在HashMap中,當發生哈希衝突且key不同時,追加到鏈表尾部或紅黑樹中的詳細機制如下:
1. 追加到鏈表尾部(Java 8之前)
- Java 8之前,HashMap使用「頭插法」將新節點插入到鏈表頭部
- Java 8及以後,改為使用「尾插法」將新節點追加到鏈表尾部
- 這樣做的主要原因是避免在多線程環境下可能導致的鏈表成環問題,同時配合紅黑樹優化,使查詢性能更穩定
2. 紅黑樹轉換機制
當滿足以下兩個條件時,鏈表會轉換為紅黑樹:
- 鏈表長度超過閾值(默認為8)
- 數組長度大於等於64(如果數組長度小於64,會先進行擴容而不是樹化)
3. 紅黑樹插入過程
當需要將新節點插入到紅黑樹時:
- 轉換條件檢查:首先檢查是否滿足樹化條件,不滿足則仍使用鏈表
- 樹化操作:如果鏈表長度≥8且數組長度≥64,則調用
treeifyBin()方法將鏈表轉換為紅黑樹 -
紅黑樹插入規則:
- 將鍵值對包裝為TreeNode類型節點
- 根據key的hashCode和equals方法確定插入位置
- 按照紅黑樹的插入規則(先作為二叉搜索樹插入,然後進行着色和旋轉以保持紅黑樹性質)
- 在紅黑樹中,節點按key的哈希值和比較結果排序,當hash值相同時會調用key的compareTo方法(如果實現了Comparable)或使用System.identityHashCode
4. 退化機制
當紅黑樹中的節點數量減少到6個以下時,會自動退化為鏈表,以節省內存空間
5. 性能對比
- 鏈表查詢時間複雜度:O(n),適用於衝突較少的場景
- 紅黑樹查詢時間複雜度:O(log n),適用於衝突較多的場景
- 這種自適應的結構確保了HashMap在不同數據分佈情況下都能保持較好的性能