子类必须根据是否新增参与相等判断的字段及是否维持equals五项契约来决定是否重写equals和hashcode;新增字段时须重写并同步更新hashcode,类型检查统一用getclass(),父类变更需子类同步验证,无新增逻辑时可直接继承。

父类重写了 equals,子类不是“可选”重写,而是**必须按规范决定是否重写、如何重写**——关键看子类是否新增了参与相等判断的字段,以及是否要维持 equals 的五项契约(尤其是对称性、传递性)。不处理,集合行为就会出错。
子类新增字段时,必须重写 equals 和 hashCode
如果子类加了新字段(比如 String department),且这个字段会影响“两个对象是否相等”的业务逻辑,那仅靠父类的 equals 就不够了:它根本不知道这个字段,自然不会比较它。
- 只用父类
equals,会导致两个实际内容不同的子类对象被判定为相等(漏判差异) - 更严重的是,若没同步更新
hashCode,这两个对象可能被放进HashSet的不同桶里,造成“明明相等却查不到” - 正确做法:子类
equals中先调super.equals(obj)校验父类部分,再强制转型后比较自有字段;hashCode必须用Objects.hash(super.hashCode(), 新字段)或完整重新计算
类型检查必须统一用 getClass(),不能混用 instanceof
父类若用了 instanceof Parent,子类又用 getClass() == obj.getClass(),就会破坏对称性:父类实例 p.equals(child) 返回 true,但子类实例 child.equals(p) 却返回 false。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 安全做法是:整个继承链所有类都使用
getClass() != obj.getClass()做类型守门 - 子类重写时,
super.equals(obj)传原始obj,别传转型后的变量,否则父类内部的getClass()检查会失效 - 如果父类已错误使用
instanceof,子类单方面改getClass()无法修复问题,需推动父类修正或改用CanEqual模式
父类字段变化或逻辑调整,子类也要同步验证
即使子类没加新字段,只要父类的 equals 实现变了(比如原来只比 id,现在加了 status),子类就可能因复用旧逻辑而违反契约。
- 子类重写
equals时,必须确保super.equals(obj)调用的是当前版本的父类实现 - 建议每次修改父类
equals后,对所有子类跑一遍单元测试,重点验证set.contains(等价子类对象)是否返回true - 若父类是抽象类,它的
equals应只比较自身声明的字段,并用getClass()限定类型范围,避免子类误判
不重写的合理场景:子类确实无需扩展相等逻辑
不是所有子类都必须重写。如果子类只是对父类做语义细化(如 AdminUser extends User),但“相等”仍完全由父类字段定义(比如只看 userId),那直接继承父类 equals 是正确且简洁的。
- 此时子类不必重写,但必须确认父类的
equals已严格满足契约,且hashCode覆盖了全部参与比较的字段 - 可用
@Override注解显式声明“我继承父类实现”,避免被误认为遗漏 - 若未来子类需要新增字段,再重写也不迟——但那时必须同步更新
hashCode并回归测试
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










