HashMap 是 Java 中常用的哈希表实现,其扩容机制是保证哈希表性能的关键。当 HashMap 中的元素数量达到一定阈值时,会触发扩容操作,以减少哈希冲突,提高操作效率。以下是其扩容机制的详细说明:
1. 扩容触发条件
HashMap 扩容的核心判断条件是:当前元素数量(size) > 容量(capacity) × 负载因子(loadFactor)
- 容量(capacity):哈希表的当前长度,默认为 16,且始终保持为 2 的幂
- 负载因子(loadFactor):默认值为 0.75,用于平衡空间与时间效率
- 阈值(threshold):capacity × loadFactor,当 size 超过此值时触发扩容
2. 扩容过程
- 计算新容量:新容量 = 原容量 × 2(保持 2 的幂特性)
- 创建新哈希表:根据新容量创建一个更大的数组
- 重新哈希(rehash):将原哈希表中的所有元素重新计算哈希值,并放入新数组中
- 由于容量变为原来的 2 倍,元素在新数组中的索引可通过 原索引 + 原容量 计算得出(优化后的位运算)
- 更新属性:将新数组、新容量、新阈值(新容量 × 负载因子)赋值给当前 HashMap
3. 关键代码逻辑(简化版)
java
运行
void resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
// 计算新容量和新阈值
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
// 新容量 = 旧容量 × 2
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // 新阈值 = 旧阈值 × 2
}
// 创建新数组
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
// 重新哈希所有元素到新数组
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
else {
// 处理链表或红黑树的拆分
// ...
}
}
}
}
threshold = newThr;
}
4. 扩容的影响
- 优点:扩容后哈希表容量增大,哈希冲突概率降低,查询、插入等操作效率提升
- 缺点:扩容过程需要重新哈希所有元素,会消耗额外的时间和资源,尤其是在元素数量较多时
5. JDK 1.8 后的优化
- 当链表长度超过 8 且数组容量 ≥ 64 时,会将链表转为红黑树,避免链表过长导致查询效率下降
- 重新计算索引时利用位运算特性(
e.hash & (newCap - 1)),优化了元素迁移逻辑
理解 HashMap 的扩容机制,有助于在实际开发中根据业务场景合理设置初始容量和负载因子,从而优化哈希表的性能。
HashMap扩容机制全解析
1302

被折叠的 条评论
为什么被折叠?



