Java集合判等依赖equals与hashCode协同:equals决定逻辑相等性并须遵守五大契约,hashCode提供哈希分组依据且要求equals为真时哈希值必相同;HashSet/HashMap先哈希定位再equals比对,ArrayList仅用equals;推荐用IDE或Lombok生成以确保正确性。

Java集合判等的核心是equals与hashCode方法的协同工作,不是简单比较内存地址,而是依赖对象逻辑相等性。理解二者如何配合,是避免HashSet漏存、HashMap查不到、ArrayList.contains失效等问题的关键。
equals方法决定“两个对象是否相等”
equals用于明确语义上的相等判断。默认继承自Object,仅做引用比较(==),对大多数业务对象不适用。
- 必须重写
equals才能让集合按业务规则判等,比如两个User对象只要id相同就视为同一人 - 重写需遵守五大契约:自反性、对称性、传递性、一致性、对
null返回false - 典型写法:先用
==判自身,再用instanceof检查类型,最后逐字段比较(注意处理null和浮点误差)
hashCode方法为哈希集合提供“快速分组依据”
hashCode本身不判等,但它决定了对象在HashMap/HashSet中存放的桶位置。如果两个对象equals为true,它们的hashCode必须相同;反之不成立。
- 未重写
hashCode时,不同对象几乎总返回不同哈希值,导致本该同桶的对象被散列到不同桶里——contains永远找不到 - 重写时应选用不变的、参与
equals判断的字段来计算,常用Objects.hash(field1, field2)生成 - 避免用可变字段(如普通setter修改的属性)参与哈希计算,否则对象入集合后修改字段,会导致再也无法被定位
集合内部如何联动这两个方法
不同集合策略不同,但核心逻辑一致:
立即学习“Java免费学习笔记(深入)”;
-
HashSet.add(e):先算e.hashCode()定位桶,再遍历桶内元素,用equals逐一比对——只有哈希值相同且equals为true才拒绝重复 -
HashMap.get(key):同样先哈希定位,再在对应链表/红黑树中用equals找真正匹配的key -
ArrayList.contains(e)不依赖hashCode,只调用equals顺序遍历——所以即使忘了重写hashCode,它也可能“看似正常”,但这只是假象,换到哈希集合就暴露问题
IDE和Lombok帮你安全生成
手写容易出错,推荐工具辅助:
- IntelliJ:右键 →
Generate→ 勾选字段 → 自动生成符合契约的equals和hashCode - Lombok:加
@EqualsAndHashCode注解,默认包含所有非静态非瞬态字段;可指定include或exclude字段,更可控 - 注意:若类有继承关系,父类也参与判等,需显式调用
super.equals和super.hashCode,Lombok默认不处理这点,需手动配置









