重写 equals 方法必须同时重写 hashCode,否则 HashMap、HashSet 等集合中会出现查找失败或重复插入;equals 中需先判空和类型,用 Objects.equals 比较字段,浮点数用 Double.compare,数组用 Arrays.equals。

重写 equals 方法必须同时重写 hashCode
不重写 hashCode 会导致对象在 HashMap、HashSet 等集合中行为异常——比如两个逻辑相等的对象无法被正确查找到,或重复插入。Java 规范明确要求:如果 equals 返回 true,那么这两个对象的 hashCode 必须相等。
常见错误现象:Set.add(obj1); Set.contains(obj2) 返回 false,尽管 obj1.equals(obj2) 是 true。
- 先写
equals,再用 IDE(如 IntelliJ)自动生成hashCode,别手写 - 确保
hashCode计算只依赖equals中用到的字段 - 若字段为引用类型,优先用
Objects.hash(field1, field2),它会自动处理null
equals 方法里必须做 null 和类型检查
直接调用 other.field 或 other.toString() 前没校验,运行时抛 NullPointerException 或 ClassCastException 是高频问题。
典型错误写法:if (this.name.equals(other.name)) —— other 可能是 null 或不是本类实例。
- 第一行必须是
if (this == other) return true(同一对象引用) - 第二行必须是
if (other == null || getClass() != other.getClass()) return false - 不要用
instanceof判类型(子类调用父类equals时可能破坏对称性) - 字段比较用
Objects.equals(field1, field2),它安全处理null
浮点数、数组、嵌套对象的相等判断不能用 == 或默认 equals
double 字段用 == 比较会因精度误差误判;double[] 用 .equals() 实际比较的是引用;嵌套的自定义对象若没重写 equals,也会走 Object 默认实现(即地址比较)。
- 浮点字段用
Double.compare(d1, d2) == 0或Math.abs(d1 - d2) - 数组字段用
Arrays.equals(arr1, arr2)(一维)或Arrays.deepEquals(arr1, arr2)(多维) - 嵌套对象字段仍用
Objects.equals(nested1, nested2),前提是该类已正确定义equals
Lombok 的 @EqualsAndHashCode 不是万能解药
它省代码,但容易掩盖语义问题:比如把数据库主键 id 加入 equals 计算,会导致新构造但未保存的对象永远不等于已有对象;又或者漏掉业务关键字段(如 status),让不同状态的订单被当成同一个。
- 显式指定
exclude或of,例如@EqualsAndHashCode(of = {"orderId", "itemId"}) - 避免包含可变字段(如
lastModifiedTime),否则对象加入HashSet后修改该字段,集合结构就损坏了 - 如果类有继承关系,Lombok 默认不生成父类字段参与比较的逻辑,需手动加
callSuper = true并确认父类equals行为合理
字段顺序、null 安全、集合一致性、业务语义——这四点没对齐,equals 就只是看起来在工作。

















