You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HashMap使用可变对象作为键的迭代行为异常原因咨询

问题根源:混淆了「引用变量」和「实际存储的对象」

你遇到的困惑核心在于没搞清楚Java中引用变量和它指向的实际对象之间的区别,以及HashMap存储键的本质。咱们一步步拆解你的操作和现象:

1. 初始存储阶段:HashMap存的是对象,不是变量

当你执行:

Employee e1 = new Employee("sachin",123);
map.put(e1, "lo");

HashMap里存储的是new Employee("sachin",123)这个实际对象,而不是e1这个变量。e1只是一个指向这个对象的"指针"而已。同理,e2和e3指向的对象也被存入了map,但因为e2和e3的equals()返回true、hashCode()相同,所以put(e3)会覆盖e2对应的value,此时map里实际有两个键对象:

  • 对象A:name=sachin, id=123(最初e1指向的对象)
  • 对象B:name=sachin, id=456(e2和e3指向的对象)

2. 改变e1的指向:不会影响HashMap里的对象

当你执行:

e1= new Employee("hrithik",123);

这只是让e1这个指针重新指向了一个新的对象C,但原来的对象A依然好好待在HashMap里,没有任何变化。所以此时map.get(e1)返回null,是因为对象C不在map里,这符合预期。

接着你执行:

e1=e2;

这只是让e1现在指向对象B(和e2指向同一个对象),但HashMap里的对象A还是存在的——你只是改变了e1的指向,并没有从map里移除对象A,也没有修改对象A的内容。

3. 迭代时看到旧内容的原因

所以当你迭代map的键时,看到name=sachin, id=123的对象,就是最初的对象A,它从来没被修改或移除过。e1只是不再指向它了,但它依然是HashMap的键之一,自然会被迭代出来。

4. 修改对象B的empId后的现象

当你执行:

e2.setEmpId(300);

这是直接修改了对象B的属性(因为e2指向对象B,而对象B是HashMap里的键)。此时对象B的equals()逻辑会因为empId变化而改变,但你的hashCode()计算只依赖name的属性,所以hashCode不变。这会导致:

  • HashMap无法通过get()方法正确找到对象B(因为equals条件变了,但它还在原来的桶里)
  • 迭代时依然能看到对象B,因为迭代是遍历所有桶,不管键的hashCode和equals是否匹配当前状态

总结关键知识点

  • HashMap存储的是对象本身的引用,不是你用来指向对象的变量。变量的赋值只是改变指针指向,不会影响HashMap里已存储的键。
  • 如果要替换HashMap的键,你需要先调用map.remove(oldKey)移除旧键,再调用map.put(newKey, value)添加新键,而不是单纯改变变量的指向。
  • 作为HashMap键的对象,尽量不要修改影响hashCode()或equals()的属性——如果必须修改,修改后要先移除旧键再重新存入,否则会导致HashMap的键"失效"(无法通过get找到,但仍存在于map中)。

内容的提问来源于stack exchange,提问作者user1600902

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:13:23