重写equals方法必须前置空值检查,第一步用obj==null判空,第二步用getclass()校验类型,第三步用objects.equals安全比较字段,并同步重写hashcode。

在重写 equals 方法时,空值检查不是“可选优化”,而是必须前置的防御性步骤。忽略它会导致 NullPointerException,破坏方法契约(比如违反自反性、对称性),也违背《Effective Java》中“先检查 null”的明确建议。
第一步:用 == 判断 this 和 obj 是否为同一引用或是否为 null
这是最高效、最安全的起点。用 == 既能快速捕获自反性(obj == this),又能一次性处理 this 或 obj 为 null 的情况——注意:this 永远不为 null(实例方法调用前提),但显式写 obj == null 更清晰且符合惯例。
-
正确写法:
if (obj == null) return false; -
错误写法:
if (this == null) ...(语法非法,this 不可能为空) -
不推荐写法:
if (obj == null || this == null)(冗余且误导)
第二步:用 getClass() 做运行时类型严格校验
如果希望 equals 具备“严格类型一致性”(即子类对象不能与父类对象相等),必须用 getClass() == obj.getClass(),而不是 instanceof。后者会破坏对称性:假设 A extends B,a.equals(b) 可能为 true,但 b.equals(a) 因类型不同返回 false。
-
严格场景(推荐):
if (getClass() != obj.getClass()) return false; -
宽松场景(如 JPA 实体):若需支持子类参与比较,才考虑
instanceof,但需配套重写hashCode并谨慎设计契约
第三步:强制转型后逐字段比较,注意字段本身的 null 安全
转型前已确保非 null 且类型一致,此时可安全强转。但字段本身可能是引用类型,直接调用 .equals() 仍可能抛 NPE。应使用 Objects.equals(a, b) —— 它内部自动处理任一参数为 null 的情况,返回 true(当两者都为 null)或 false(仅一个为 null)。
-
安全写法:
return Objects.equals(field1, other.field1) && Objects.equals(field2, other.field2); -
危险写法:
field1.equals(other.field1)(field1 为 null 时崩溃) -
替代方案:手动判空,如
(field1 == null ? other.field1 == null : field1.equals(other.field1)),但更啰嗦易错
补充:不要忘记重写 hashCode
只要重写了 equals,就必须重写 hashCode,否则违反 “相等对象必须有相同哈希码” 的契约,导致在 HashMap、HashSet 中行为异常。可用 Objects.hash(field1, field2, ...) 快速生成一致哈希值。
-
关键原则:参与
equals比较的所有字段,必须全部参与hashCode计算 -
工具辅助:IDE(如 IntelliJ)可一键生成符合规范的
equals和hashCode方法,内置 null 安全逻辑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











