HashMap 底层是"数组 + 链表 + 红黑树"的哈希表结构。
核心机制:内部维护一个 Node 数组(桶),默认初始容量 16,负载因子 0.75。put 时对 key 的 hashCode 做扰动(高 16 位与低 16 位异或),再与容量取模定位桶位;桶空直接放入,发生哈希冲突则以链表挂在桶后;当单个桶链表长度达到 8 且数组长度 ≥ 64 时链表树化为红黑树,把冲突时的查询从 O(n) 降到 O(log n);元素少于 6 时退化为链表。元素总数超过容量×负载因子时扩容为 2 倍并重新散列(JDK 8 优化:旧链表的节点只需判断高位 bit,决定留在原位置或移动到原位置+旧容量)。容量总是 2 的幂,使取模可用位运算代替。
要点:HashMap 非线程安全,多线程下 JDK 7 扩容可能成环、JDK 8 会丢数据;允许 null key(放在 0 号桶);JDK 7 用头插法、JDK 8 改尾插法。
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
追问方向:为什么容量必须是 2 的幂?为什么树化阈值是 8(泊松分布)?
(约 370 字)