重写 equals 方法必须严格遵守 Java 规范的五项契约:自反性、对称性、传递性、一致性及对 null 的处理;标准实现需依次检查引用相等、判空与类型、强制转换、字段比较(用 Objects.equals 等);仅包含决定业务相等性的不可变字段,并同步重写 hashCode。

重写 equals 方法不是加个判断就行,而是要守住 Java 规范定义的五项契约,否则在集合操作、序列化、框架集成中会出隐蔽且难排查的问题。
必须满足的五个基本约定
Java 要求 equals 必须同时满足:
-
自反性:任意非 null 对象
x,x.equals(x)必须返回true -
对称性:若
x.equals(y)为true,则y.equals(x)也必须为true -
传递性:若
x.equals(y)和y.equals(z)都为true,则x.equals(z)必须为true - 一致性:只要参与比较的字段未变,多次调用结果不能变
-
对 null 的处理:任何非 null 对象调用
x.equals(null)必须返回false
标准实现步骤(按顺序不可跳)
以 Person 类为例(含 id、name、age):
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
- 先检查引用相等:
if (this == obj) return true;(性能优化) - 再判空和类型:
if (obj == null || getClass() != obj.getClass()) return false;(用getClass(),不用instanceof,避免继承下破坏对称性) - 强制转换:
Person other = (Person) obj; - 字段逐一对比:
- 基本类型(如
int、boolean)直接用== - 引用类型(如
String、自定义对象)统一用Objects.equals(a, b)(自动防null) - 浮点数(
double/float)用Double.compare(a, b) == 0,不用== - 数组用
Arrays.equals(arr1, arr2),多维用Arrays.deepEquals
- 基本类型(如
哪些字段不该参与比较?
只保留真正决定“业务上是否相等”的字段:
立即学习“Java免费学习笔记(深入)”;
- ✅ 推荐:主键(
id)、唯一标识(orderNo)、核心属性(name、email) - ❌ 排除:临时状态(
isLoaded)、缓存字段、数据库时间戳(createdAt)、可变统计值(viewCount) - ⚠️ 警惕:如果字段后续可能被修改(如未
final),放入equals后再改会导致已加入HashSet的对象“消失”
必须同步重写 hashCode
equals 和 hashCode 是绑定契约:
- 如果
a.equals(b)返回true,那么a.hashCode() == b.hashCode()必须成立 -
hashCode只能基于equals中实际比较的字段计算,推荐写法:return Objects.hash(id, name); - 不要手写哈希算法,避免遗漏字段或误用可变字段

















