正确实现 equals 和 hashcode 需用 getclass() 做类型检查、子类调用 super.equals(obj) 时传原始 obj、hashcode 覆盖所有参与比较的字段,且避免可变字段参与。

在继承体系中正确实现 equals 和 hashCode,核心是保证“相等性契约”不被破坏:两个对象若 equals 返回 true,它们的 hashCode 必须相同;且该行为在父类、子类间保持一致、对称、可传递。
类型检查必须用 getClass(),不能用 instanceof
使用 getClass() != obj.getClass() 能确保子类和父类互不相等(例如 SubClass 实例不等于 SuperClass 实例),避免违反对称性和传递性。如果父类用了 instanceof,子类调用 super.equals(obj) 会出错——此时子类必须整体重写,不能依赖父类逻辑。
- ✅ 正确:
if (obj == null || getClass() != obj.getClass()) return false; - ❌ 危险:
if (!(obj instanceof SuperClass)) return false;(会导致子类实例与父类实例意外相等)
子类 equals 中调用 super.equals() 要传原始 obj
父类的 equals 方法内部仍需做自己的类型检查和字段比较。子类在复用时,应直接传入未转型的 obj,而不是转型后的引用,否则父类里 getClass() 检查会失败。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- ✅ 正确:
if (!super.equals(obj)) return false; - ❌ 错误:
if (!super.equals(that)) return false;(that是子类转型后对象,父类无法识别)
hashCode 必须覆盖所有参与 equals 比较的字段
父类和子类的 hashCode 都要包含各自用于 equals 判定的全部字段。不能只调用 super.hashCode() 再叠加子类字段——除非父类的 hashCode 本身已严格基于其参与 equals 的字段计算。
- 父类示例:
return Objects.hash(id, name); - 子类示例:
return Objects.hash(super.hashCode(), radius, color);或更稳妥地return Objects.hash(id, name, radius, color); - ⚠️ 注意:漏掉任一字段,对象放入
HashSet或作HashMapkey 时可能丢失或重复
避免可变字段参与 equals 和 hashCode
一旦对象被用作集合的 key 或存入 HashSet,其参与 equals 和 hashCode 的字段就不应再修改。否则哈希桶位置错乱,导致 contains 找不到、get 返回 null 等静默故障。
- 推荐将参与比较的字段设为
final(尤其在值对象场景) - 若业务必须可变,需确保修改前从集合中移除,修改后再重新加入
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










