hashmap查找键的本质是先用hashcode定位桶,再用equals确认匹配;若只重写equals,相同对象可能散列到不同桶导致查不到;若只重写hashcode,则因默认equals比较地址而永远不相等。

Java 中 HashMap 查找键的过程,本质是 先用 hashCode 定位,再用 equals 确认。它不是直接比内存地址,也不是只靠其中一个方法——两个方法必须协同工作,缺一不可。
hashCode 决定“去哪个桶里找”
HashMap 底层是一个数组加链表(或红黑树)的结构。当你 put 或 get 一个键时:
- 先调用键对象的
hashCode()方法,得到一个整数 - 用这个整数对数组长度取模(如
hash % table.length),算出它该落在哪个索引位置(也就是“桶”) - 如果那个桶里已经存了其他键,就说明发生了哈希冲突,需要进一步比较
equals 决定“是不是你要找的那个键”
进入对应桶之后,HashMap 会遍历里面的节点(可能是链表或树节点):
- 对每个已有键调用
equals()方法,和当前要查找的键做逻辑比较 - 只要某次
equals()返回true,就认为找到了匹配的键,操作(如 get、put 覆盖)立即结束 - 如果遍历完都没匹配上,才认为键不存在
为什么必须同时重写且逻辑一致
这两个方法之间有严格契约:
- 如果
a.equals(b) == true,那么a.hashCode() == b.hashCode()必须成立 - 反过来不强制:
hashCode()相同,equals()可以是 false(哈希冲突允许) - 参与
equals()比较的字段,必须全部参与hashCode()计算 - 不能只重写
equals():否则相同逻辑的键可能被散列到不同桶,get()永远查不到 - 不能只重写
hashCode():所有键挤在一个桶里,退化成线性查找,且equals()还是按默认引用比较,永远不相等
怎么验证重写是否生效
别只看编译通过,写个简单测试最可靠:
- 创建两个内容完全相同的自定义对象(比如 new Person("Tom", 30) 和 new Person("Tom", 30))
- 放进 HashMap:
map.put(p1, "value") - 用另一个实例去取:
map.get(p2)—— 应该返回 "value" - 检查大小:
map.size()—— 应该是 1,不是 2
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











