HashMap、HashSet、HashTable实现原理解析

119 阅读2分钟

一、HashMap

1. 核心实现原理

  • 数据结构:数组 + 链表/红黑树(JDK8+)
  • 初始容量:默认16(DEFAULT_INITIAL_CAPACITY
  • 负载因子:默认0.75f(DEFAULT_LOAD_FACTOR
  • 扩容机制:当size > capacity * loadFactor时扩容为2倍

2. 关键特性

// 典型存储结构
transient Node<K,V>[] table;  // 数组桶

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;  // 链表结构
}

3. 工作流程

  1. 计算哈希(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)
  2. 确定桶位(n - 1) & hash
  3. 处理冲突
    • 链表:遍历查找,JDK8尾插法
    • 红黑树:当链表长度≥8且数组长度≥64时转换
  4. 扩容机制
    • 创建新数组(2倍原大小)
    • 重新计算位置:e.hash & (newCap - 1)
    • JDK8优化:节点位置=原位置 或 原位置+原容量

4. 重要参数

参数默认值说明
TREEIFY_THRESHOLD8链表转红黑树阈值
UNTREEIFY_THRESHOLD6红黑树退化为链表阈值
MIN_TREEIFY_CAPACITY64最小树化容量

二、HashSet

1. 核心实现

// 实际使用HashMap存储
private transient HashMap<E,Object> map;

// 虚拟值对象
private static final Object PRESENT = new Object();

2. 关键特性

  • 元素唯一性:利用HashMap键的唯一性
  • 操作实现
    public boolean add(E e) {
        return map.put(e, PRESENT) == null;
    }
    
  • 无序存储:依赖HashMap的哈希分布
  • 线程不安全:与HashMap特性一致

三、HashTable

1. 核心实现

  • 数据结构:数组 + 链表(无红黑树优化)
  • 初始容量:默认11
  • 负载因子:默认0.75
  • 扩容机制newCapacity = (oldCapacity << 1) + 1

2. 线程安全实现

public synchronized V put(K key, V value) {
    // 方法级synchronized保证线程安全
}

3. 与HashMap对比

特性HashTableHashMap
线程安全✅ 方法级synchronized
Null处理不允许null键/值允许一个null键,多个null值
哈希计算直接使用key.hashCode()二次哈希(h = key.hashCode()) ^ (h >>> 16)
继承体系继承Dictionary类实现AbstractMap接口
迭代器Enumerator(不支持fail-fast)Iterator(支持fail-fast)

四、对比总结

特性HashMapHashSetHashTable
实现接口MapSetMap
底层结构数组+链表/红黑树HashMap数组+链表
线程安全
Null支持
迭代顺序不保证有序不保证有序不保证有序
初始容量161611
扩容倍数2倍依赖HashMap2倍+1
哈希冲突解决链表/红黑树同HashMap链表
性能低(同步开销)
推荐使用场景单线程环境元素去重遗留系统维护

五、使用建议

  1. 首选HashMap:单线程环境下性能最优
  2. 线程安全替代
    • ConcurrentHashMap 替代 HashTable
    • Collections.synchronizedMap() 包装HashMap
  3. HashSet适用场景
    // 元素去重示例
    Set<String> uniqueWords = new HashSet<>();
    for (String word : words) {
        uniqueWords.add(word);
    }
    
  4. HashTable遗留问题
    • 性能瓶颈(全局锁)
    • 已被ConcurrentHashMap取代

:JDK8+中HashMap的红黑树优化显著提升了哈希冲突严重时的查询效率(时间复杂度从O(n)优化到O(log n))。