Java HashMap 扩容原理实战:负载因子、树化阈值与初始容量到底怎么设
Java HashMap 扩容原理实战:负载因子、树化阈值与初始容量到底怎么设new HashMap()你写了无数遍,但很少有人想过一个问题:往里塞 1000 个元素,这个 HashMap 到底扩容了几次?每次扩容做了什么?为什么面试官老爱问「初始容量给多少合适」?这不是背八股文,是真会影响性能的东西。一次扩容意味着重新分配数组、把所有元素挪个位置,批量插入时如果反复扩容,吞吐会明显掉。这篇我们把 HashMap 的扩容机制讲清楚,并给出「初始容量到底怎么算」的可落地公式。三个关键数字:容量、负载因子、阈值HashMap 内部是一个数组(叫table),每个格子叫一个「桶」(bucket)。三个概念要先分清:容量(capacity):数组的长度,永远是 2 的幂(16、32、64…)。默认初始 16。负载因子(load factor):默认0.75。它决定「数组用到多满就扩容」。阈值(threshold):容量 × 负载因子。元素个数超过它就触发扩容。默认16 × 0.75 12。也就是说,默认的 HashMap 塞到第 13 个元素时就会第一次扩容:数组从 16 变成 32,阈值从 12 变成 24。验证一下(用反射偷看内部数组长度):importjava.lang.reflect.Field;importjava.util.HashMap;publicclassResizeDemo{staticinttableLength(HashMap?,?map)throwsException{FieldfHashMap.class.getDeclaredField(table);f.setAccessible(true);Object[]table(Object[])f.get(map);returntablenull?0:table.length;}publicstaticvoidmain(String[]args)throwsException{HashMapInteger,IntegermapnewHashMap();System.out.println(初始 table: tableLength(map));// 0,懒初始化for(inti0;i13;i){map.put(i,i);System.out.println(put i - table 长度 tableLength(map));}}}输出会看到:第一次put时数组才从 0 变成 16(懒初始化,new的时候不分配),塞到第 13 个(i12)时数组变成 32。这就是扩容发生的确切时刻。扩容做了什么:rehash扩容不是简单地把数组变长,而是要把每个元素重新分配到新数组的桶里——这个过程叫 rehash。元素落在哪个桶,由hash (capacity - 1)决定(容量是 2 的幂,所以能用位与代替取模,快)。容量翻倍后,capacity - 1的二进制多了一个高位 1,于是每个元素要么留在原来的桶,要么移动到「原索引 旧容量」的桶。JDK 8 对此做了优化:不用重新算 hash,只需看那个新增的高位 bit 是 0 还是 1 就能决定去留,省了重复计算。关键结论:扩容 分配双倍数组 遍历所有元素重新分桶。这是个 O(n) 操作。如果你能预知要放多少元素,一次性给够初始容量,就能完全避免中途反复扩容。初始容量到底怎么设:别直接填元素个数最常见的错误:「我要放 100 个元素,那就new HashMap(100)」。错了。因为负载因子 0.75 的存在,容量 100 塞到第 76 个(100×0.7575)就又扩容了。正确的公式是:初始容量 期望元素数 / 0.75 1,再让 HashMap 向上取整到 2 的幂。intexpected100;// 官方推荐算法:确保放 expected 个元素也不会触发扩容intinitialCapacity(int)(expected/0.75f)1;HashMapString,ObjectmapnewHashMap(initialCapacity);100 / 0.75 1 134,HashMap 会向上取整到 256(2 的幂),阈值256 × 0.75 192 100,放 100 个绝不扩容。JDK 19 更省心,直接有个工厂方法帮你算好:// Java 19 : 参数直接是期望元素数,内部自动换算容量MapString,ObjectmapHashMap.newHashMap(100);如果还在用 JDK 8~18,就老老实实用(int)(n / 0.75) 1这个公式。树化:链表什么时候变红黑树当多个 key 的 hash 冲突落到同一个桶,它们会先串成链表。链表长了查找就退化成 O(n)。JDK 8 引入了优化:一个桶里的链表长度达到 8,且数组容量 ≥ 64 时,链表转成红黑树,查找回到 O(log n)。这里有个容易记错的点:链表长度到 8 只是条件之一。如果此时数组容量 64,HashMap 会优先扩容而不是树化——因为容量小时冲突多,扩容能更便宜地分散冲突。只有容量 ≥ 64 且某桶链表 ≥ 8,才真的树化。反过来,红黑树节点数退回到 6 以下(比如删除元素),会退化回链表。所以「链表超过 8 就变红黑树」这句流传的说法不完整,少了「容量 ≥ 64」这个前提。// 树化的两个阈值(HashMap 源码里的常量)// static final int TREEIFY_THRESHOLD 8; // 链表转树// static final int UNTREEIFY_THRESHOLD 6; // 树退化回链表// static final int MIN_TREEIFY_CAPACITY 64; // 容量不够先扩容负载因子该不该改new HashMap(16, 0.5f)能自定义负载因子,但绝大多数情况不要动。它是空间和时间的权衡:调小(如 0.5):更早扩容,桶更稀疏,冲突少查询快,但更费内存、扩容更频繁。调大(如 0.9):更晚扩容,省内存,但冲突概率上升,查询变慢。0.75 是官方在时间和空间之间选的平衡点,基于泊松分布算过冲突概率。除非你有实测数据证明特定场景收益明显,否则保持默认。真正值得你调的是初始容量,而不是负载因子。小结HashMap 容量永远是 2 的幂,默认 16;阈值 容量 × 负载因子(默认 0.75),超过就扩容,数组翻倍。默认从第13个元素开始第一次扩容;扩容是 O(n) 的 rehash,批量插入时反复扩容会拖慢性能。设初始容量别直接填元素数,用(int)(n / 0.75) 1;JDK 19 直接HashMap.newHashMap(n)。树化需要两个条件:桶内链表 ≥ 8且数组容量 ≥ 64;容量不够时优先扩容而非树化。负载因子保持默认 0.75,该调的是初始容量。一句话记忆:能预估元素个数时,就用(int)(n/0.75)1给足初始容量,把「反复扩容 rehash」这个隐形成本一次性消掉。

相关新闻

Go 用 bufio.Scanner 读大文件踩坑:默认 64KB 行上限、Buffer 扩容与按 Token 切分

Go 用 bufio.Scanner 读大文件踩坑:默认 64KB 行上限、Buffer 扩容与按 Token 切分

Go 用 bufio.Scanner 读大文件踩坑:默认 64KB 行上限、Buffer 扩容与按 Token 切分 用 Go 逐行读文件,几乎所有人第一反应都是 bufio.Scanner,写法也确实优雅: scanner : bufio.NewScanner(file) for scanner.Scan() {line : scanner.Text()// 处理每一行 }小文件跑得好好的,直…

2026/10/15 21:02:20 阅读更多 →
终极指南:如何在浏览器中免费畅玩开源三国杀网页版

终极指南:如何在浏览器中免费畅玩开源三国杀网页版

终极指南:如何在浏览器中免费畅玩开源三国杀网页版 【免费下载链接】noname 项目地址: https://gitcode.com/GitHub_Trending/no/noname 还在为下载安装繁琐的三国杀客户端而烦恼吗?想要随时随地与朋友来一局经典的三国杀对战吗?开源…

2026/10/14 22:33:39 阅读更多 →
TradeNote完全指南:如何用开源交易日志提升你的交易一致性与盈利能力

TradeNote完全指南:如何用开源交易日志提升你的交易一致性与盈利能力

TradeNote完全指南:如何用开源交易日志提升你的交易一致性与盈利能力 【免费下载链接】TradeNote TradeNote is an open source trading journal that helps traders store, discover and recollect all their trades so they can become and remain consistent and…

2026/10/16 19:47:42 阅读更多 →

最新新闻

初中物理虚拟实验教学资源包实用指南:仿真交互与课堂落地

初中物理虚拟实验教学资源包实用指南:仿真交互与课堂落地

简介:面向初中生的NB初中物理虚拟实验平台,是一套基于计算机仿真技术的互动教学资源,适合学生、教师及实验条件有限的学校使用。资源围绕力学、热学、光学、电学、声学、能量转换、简单机械等内容设计,通过模拟真实实验环境&#…

2026/10/16 20:32:59 阅读更多 →
Maya层编辑器实战:显示层/渲染层/批渲染脚本全攻略

Maya层编辑器实战:显示层/渲染层/批渲染脚本全攻略

如果你也靠Maya做场景类项目,层编辑器这个东西迟早得认真对待。我在一个做了大半年的城市场景Demo里吃过不少苦头:Outliner里的节点从几百长到两三千,角色、建筑、路灯、参考模型全部搅在一起;想临时隐藏一片屋顶,Ctrl…

2026/10/16 20:32:59 阅读更多 →
汉字笔顺动画教学系统:基于国标规范的交互式训练实践

汉字笔顺动画教学系统:基于国标规范的交互式训练实践

简介:Hanzi Writer 是一个基于 TypeScript 开发的开源汉字笔画顺序动画与练习测验 JavaScript 库,面向中文学习者、教育类应用开发者及前端技术实践者,解决汉字书写规范可视化与交互式训练缺失的问题,特别适配简繁体字教学场景。资…

2026/10/16 20:31:58 阅读更多 →
EAC抓轨实战:精确流、偏移校正与无损FLAC转换全解析

EAC抓轨实战:精确流、偏移校正与无损FLAC转换全解析

简介:EAC CD抓轨软件压缩包是一套面向音频发烧友、音乐收藏者及数字音频制作者的经典抓轨工具,专为解决CD音轨提取时易出现的读取错误、音质损耗等问题。软件采用安全抓轨机制,能最大限度保留原始声音,支持FLAC、WAV、AAC等多种编…

2026/10/16 20:31:58 阅读更多 →
蓝色立体三角形多边形PPT背景图:选图、排版与避坑指南

蓝色立体三角形多边形PPT背景图:选图、排版与避坑指南

简介:蓝色立体三角形多边形PPT背景图片zip包,定位于需要快速提升演示文稿视觉效果的PPT制作者。以三角形拼合形成的立体图形为主视觉,蓝色调契合科技、商业、创新等专业主题,能将幻灯片的平面感转为更具层次与深度的空间感&#x…

2026/10/16 20:31:58 阅读更多 →
Foxmail v7.0.1.92:安装配置、数据迁移与避坑指南

Foxmail v7.0.1.92:安装配置、数据迁移与避坑指南

简介:Foxmail v7.0.1.92官方正式版是一款面向国内个人及办公用户的电子邮件客户端,解决邮件收发管理、垃圾邮件过滤和传输安全等常见问题。其反垃圾机制可自动识别并分拣垃圾邮件,数字签名与SSL加密确保邮件真实性和保密性,还支持…

2026/10/16 20:31:58 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →