@equalsandhashcode 在继承场景下存在四大陷阱:默认忽略父类字段导致 equals/hashcode 违反合约;callsuper=true 依赖父类正确实现,否则无效;与 @data 混用引发冗余警告或逻辑失效;无法细粒度控制参与比较的父类字段。

@EqualsAndHashCode 是 Lombok 中用于自动生成 equals() 和 hashCode() 方法的常用注解,用起来方便,但一旦涉及类继承,就容易掉进几个隐蔽又关键的坑。
默认不包含父类字段,equals 和 hashCode 逻辑被“截断”
这是最典型的问题。当子类使用 @Data 或 @EqualsAndHashCode(未显式配置)时,Lombok 生成的 equals() 和 hashCode() 只检查子类自己声明的字段,完全忽略从父类继承来的字段。
比如:
- 父类
BaseEntity有id和createTime - 子类
Product有name和price - 两个
Product对象id相同、name和price不同 →equals()返回false(看似合理) - 但如果
name和price恰好也相同,而id不同 → 它们仍会返回true!因为id根本没参与比较
这种行为直接违反 Java 的 equals 合约,尤其在集合操作(如 HashSet 去重、HashMap 查找)或 Stream distinct() 中会导致数据错乱。
callSuper = true 不是万能解,父类必须可安全参与比较
很多人加了 @EqualsAndHashCode(callSuper = true) 就以为万事大吉,但前提是父类自身也得有正确实现的 equals() 和 hashCode() —— 而这恰恰容易被忽略。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
常见陷阱包括:
- 父类没加任何 Lombok 注解,也没手动重写
equals/hashCode→ 继承Object默认实现,只比内存地址 → 子类即使加了callSuper = true,结果仍是错误的 - 父类用了
@Data,但本身又是另一个类的子类,而它的父类又没处理好 → 链式遗漏,越往上越不可靠 - 父类字段含
null、集合、时间类型等复杂对象,而其hashCode实现不稳定(例如用了未重写的ArrayList)→ 导致子类哈希值计算异常
与 @Data 混用时产生冗余或冲突警告
@Data 内部已包含 @EqualsAndHashCode,所以如果子类同时写:
@Data<br>@EqualsAndHashCode(callSuper = true)<br>public class Product extends BaseEntity { ... }
Lombok 编译器通常会报警告(如 “@EqualsAndHashCode is already implicitly used by @Data”),虽然不影响运行,但说明语义重复,且可能掩盖真实意图。更糟的是,若父类也用了 @Data,而子类没加 callSuper = true,那父子双方都按“仅自身字段”生成逻辑,等于双重失效。
无法灵活控制哪些父类字段参与比较
callSuper = true 是全量继承父类所有非静态非 transient 字段,但业务中常有例外:
- 父类有
version或updateTime这类“非标识性”字段,不应影响相等判断 - 父类字段是敏感信息(如
passwordHash),绝对不能参与比较 - 希望只基于
id判断相等,其余字段全部忽略
此时 callSuper = true 太粗放,必须改用更精确的方式:比如 @EqualsAndHashCode(onlyExplicitlyIncluded = true) + @EqualsAndHashCode.Include 显式标注关键字段,或者干脆弃用 @Data,拆解为 @Getter/@Setter + 手动定制 @EqualsAndHashCode。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










