hashmap put方法执行流程为:先计算键的扰动哈希值(null键为0,否则h^(h>>>16)),再通过(n-1)&hash定位桶索引;若桶空则直接插入,否则按链表或红黑树查找并更新/尾插;插入后若size超阈值则resize扩容。

Java HashMap 的 put 方法底层执行过程,核心是“计算哈希 → 定位桶位 → 处理冲突 → 可能扩容”。整个过程围绕数组 + 链表/红黑树的结构展开,不是简单覆盖或追加,而是根据键的哈希值和当前状态做精细判断。
1. 计算 key 的 hash 值(扰动处理)
HashMap 不直接用 key.hashCode(),而是对其做一次扰动:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}这样做的目的是让高16位也参与低位索引计算,减少哈希碰撞。比如两个对象 hashCode 只在高位不同,原始取模容易落到同一桶,扰动后更均匀分布。
2. 根据 hash 定位数组下标((n - 1) & hash)
HashMap 底层数组长度 n 总是 2 的幂(如 16、32、64),所以用位运算 (n - 1) & hash 替代 hash % n,效率更高。这个结果就是待插入的桶(bucket)索引。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
例如:n = 16 → n-1 = 15(二进制 1111),hash & 1111 等价于取低 4 位,结果必然落在 [0, 15] 范围内。
3. 桶中插入或更新逻辑(分情况处理)
定位到桶后,按以下顺序检查:
- 桶为空(tab[i] == null):直接新建 Node 放入该位置。
-
桶首节点 key 相等(hash 和 equals 都匹配):视为重复 key,替换旧 value,返回旧值(
put返回旧值,putIfAbsent则不替换)。 -
桶是链表(Node 类型):遍历链表:
- 找到相同 key → 更新 value;
- 遍历完没找到 → 尾插新 Node;
- 插入后链表长度 ≥ 8 且数组长度 ≥ 64 → 触发树化(转为红黑树)。
-
桶是红黑树(TreeNode 类型):调用
putTreeVal按红黑树规则插入或更新,保持平衡。
4. 插入后可能触发扩容(resize)
每次成功添加新元素(非替换),都会检查:size + 1 > threshold(阈值 = capacity × loadFactor,默认 0.75)。
- 若超限,调用
resize()创建两倍容量的新数组; - 原数组每个桶中的节点,重新计算新下标(因为 n 变了,
(newCap - 1) & hash结果可能不同); - 链表节点要么留在原下标,要么迁移到
原下标 + 旧容量(利用 2 的幂特性,只看 hash 新增的最高位是否为 1); - 红黑树节点同样重散列,过短(≤ 6)会退化回链表。
整个过程兼顾性能与一致性:哈希扰动降低碰撞,位运算加快寻址,链表+树兼顾小数据与大数据场景,扩容机制保证负载率可控。理解这些,才能真正用好 HashMap,避免并发修改、可变 key 等常见陷阱。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










