HashMap明确支持null键:不计算哈希、不调用hashCode(),直接存入table[0];get(null)也直访table[0]并用==判断key;仅允许一个null键,且get(null)==null无法区分“不存在”与“值为null”,应使用containsKey(null)准确判断。

HashMap 明确支持键为 null,不是“侥幸没报错”,而是内部有专用逻辑处理:不计算哈希、不调用 hashCode()、不走通用查找路径,全部绕过空指针风险,直接定位到固定位置。
存储时:null 键被强制存入 table[0]
调用 put(null, value) 时:
- 跳过
key.hashCode(),直接令 hash 值为 0; - 通过
0 & (table.length - 1)得到下标 0,即固定写入数组首桶(table[0]); - 如果
table[0]已有节点(比如之前也 put 过 null 键),则遍历该桶内链表或红黑树,用key == null判断是否命中——注意是 == 而非 equals(); - 命中则覆盖 value;未命中则尾插新节点(链表)或按树规则插入(红黑树);
- 整个过程不会抛
NullPointerException,哪怕 key 所属类的hashCode()方法本身会抛异常。
获取时:直奔 table[0],逐个比 key == null
调用 get(null) 时:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 不重新算 hash,不走
hash & (n-1)定位; - 直接访问
table[0],然后遍历其中所有节点; - 对每个节点,只判断
e.key == null(不是equals(),也不是compareTo()); - 找到第一个
key == null的节点,就返回其 value; - 找不到则返回
null——但这个null无法区分“键不存在”和“键存在但 value 为 null”。
关键限制与使用提醒
必须注意三点:
-
只能有一个 null 键:重复
put(null, v)不会新增条目,只会覆盖旧值; -
不能靠
get(null) == null判断 null 键是否存在:它既可能是没存过,也可能是存了put(null, null); -
准确判断请用
containsKey(null):该方法内部走专用分支,严格返回true或false。
为什么 ConcurrentHashMap 不允许 null 键?
不是技术做不到,而是并发模型不允许:
- ConcurrentHashMap 依赖返回值做状态判定(例如 CAS 操作、扩容协调);
- 若允许
null键,get(null)返回null就无法分辨是“查无此键”还是“查到了但值为 null”,容易引发竞态逻辑错误; - 为简化锁粒度和避免歧义,它在入口就拦截:
put(null, v)和get(null)都直接抛NullPointerException。










