首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

HashMap 源碼深度解析:JDK 8 引入紅黑樹優化碰撞性能

     編輯:Java 綜合教學

HashMap 源碼深度解析:JDK 8 引入紅黑樹優化碰撞性能

HashMap 是 Java 集合框架高頻使用的鍵值存儲結構。JDK 8 引入紅黑樹將鏈表最壞查找從 O(n) 降為 O(log n),顯著提升高碰撞場景性能。本文剖析核心源碼邏輯。

數據結構演進

  • JDK 7:數組 + 鏈表
  • JDK 8:數組 + 鏈表/紅黑樹(鏈表長度 ≥ 8 轉樹,≤ 6 退化為鏈表)

HashMap 結構圖

核心 Hash 算法

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

設計精妙點

  1. 高 16 位參與運算:h >>> 16 將 hashCode 高位混入低位,再異或 (^)
  2. 配合數組索引計算:(n - 1) & hash (n 為 2 的冪)
  3. 解決低位碰撞:若直接用 hashCode 取模,高位全為 0 時僅低位生效,極易碰撞

Put 流程關鍵邏輯

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // 7
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // 覆蓋舊值
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

關鍵閾值常量

static final int TREEIFY_THRESHOLD = 8;      // 鏈表轉樹閾值
static final int UNTREEIFY_THRESHOLD = 6;    // 樹退化鏈表閾值
static final int MIN_TREEIFY_CAPACITY = 64;  // 最小樹化容量,避免小數組頻繁轉換

擴容機制

  • 容量始終為 2 的冪,擴容 2 倍
  • JDK 8 優化:節點遷移不重新計算 hash,通過 (hash & oldCap) == 0 判斷留原位還是移至 newIndex = oldIndex + oldCap
  • 支持高並發擴容 (ConcurrentHashMap 分段鎖/CAS)

性能調優建議

  1. 預估容量:new HashMap<>(expectedSize) 避免多次擴容
  2. Key 實現良好 hashCode/equals:業務 Key 覆寫 hashCode 使高低位分布均勻
  3. 避免可變對象作 Key:修改字段導致 hash 改變,查找失效
  4. 高碰撞場景:考慮 IdentityHashMap 或自定義哈希策略

掌握 HashMap 源碼邏輯,不僅能應對面試,更能在實際開發中做出正確的容器選型與調優決策。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved