不能,修改可变对象key的属性后get()大概率返回null,因hashCode改变导致哈希定位失效:Entry仍留在原桶,而get()按新哈希值查找新桶,自然为空;即使equals仍成立,也因未进入同一桶而无法比对。

不能,修改可变对象 key 的属性后,get() 很大概率返回 null。这不是偶然出错,而是 HashMap 底层哈希机制决定的必然结果。
哈希定位失效:改字段 → 哈希值变 → 桶位置错
HashMap 查找分两步:
- 用
key.hashCode()算出该 key 应该在哪个桶(数组索引) - 再到那个桶里,用
equals()逐个比对 Entry 的 key 是否相等
如果 key 对象的字段被修改(且这些字段参与了 hashCode() 计算),哈希值就会改变。但 Entry 并不会自动挪到新桶里——它还留在原来的位置。下次 get() 时,HashMap 会按新哈希值去另一个桶里找,自然找不到,直接返回 null。
例如:Student s = new Student("张三", 18) 存入 map;之后调用 s.setAge(25),若 age 参与哈希计算,hashCode() 就变了。此时 map.get(s) 会去新哈希值对应的桶查找,而原 Entry 仍在旧桶中,结果就是 null。
即使 equals 还能对上,也根本走不到那一步
equals() 是否成立,只在“哈希值相同”的前提下才被调用。一旦哈希值变了,HashMap 根本不会把修改后的 key 和旧 Entry 放在同一桶里比较——它连门都没进对。所以即使你确认 s.equals(原Entry.key) 返回 true,get() 依然为空。
更隐蔽的是:entrySet 遍历仍能看到这个键值对,说明数据没丢,只是“逻辑不可达”,成了“幽灵条目”。
如何快速验证是不是哈希漂移
不靠猜,直接看哈希值:
- 存入前打印
key.hashCode(),记下数值(比如123456) - 修改字段后立即再打一次(比如变成
789012) - 两个值不同 → 就是哈希漂移导致
get()失效
真正安全的做法:让 key 不可变或与哈希解耦
不是禁止修改,而是切断修改对哈希的影响:
- 只用
final字段参与hashCode()和equals(),比如仅用id,不用name或age - 封装不可变包装类:
ImmutableStudent,构造时拷贝关键字段,全部final - 优先用 JDK 自带不可变类型:
String、Integer、UUID、LocalDate - 需要“更新 key”语义时,显式替换:
map.remove(oldKey); map.put(newKey, value)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











