子类必须显式添加@EqualsAndHashCode(callSuper = true)才能使父类字段参与equals和hashCode计算,因@Data默认callSuper = false;父类还需有正确equals/hashCode实现且字段非transient/static。

在继承关系下,Lombok 的 @EqualsAndHashCode(callSuper = true) 必须显式添加到子类上,且不能依赖 @Data 默认行为——因为 @Data 内置的 @EqualsAndHashCode 默认是 callSuper = false,即忽略父类字段。
子类必须单独声明 callSuper = true
即使父类用了 @Data 或 @EqualsAndHashCode,子类也不会自动继承其比较逻辑。Lombok 不会“向上推导”父类字段是否参与比较,必须由子类主动声明:
- ✅ 正确写法:在子类上加
@EqualsAndHashCode(callSuper = true) - ❌ 错误写法:只用
@Data(它等价于@EqualsAndHashCode(callSuper = false)) - ⚠️ 注意:
@Data和@EqualsAndHashCode(callSuper = true)可共存,但后者会覆盖前者的默认行为
父类字段参与比较的必要条件
要让父类字段真正被纳入 equals 和 hashCode 计算,还需满足两个前提:
- 父类本身必须有正确实现的
equals()和hashCode()方法(比如也用了@EqualsAndHashCode,或手写) - 父类字段不能是
transient或static(Lombok 默认跳过这两类字段) - 如果父类是抽象类或未用 Lombok 注解,建议至少加上
@EqualsAndHashCode,否则super.equals()可能退化为地址比较
典型配置示例
假设父类 BaseEntity 有 id 字段,子类 User 新增 username:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
@Data
public class BaseEntity {
private Long id;
}
@EqualsAndHashCode(callSuper = true) // 关键:显式启用父类字段
@Data
public class User extends BaseEntity {
private String username;
}
这样生成的 equals() 会先调用 super.equals() 比较 id,再比较 username;hashCode() 同理。
避免常见陷阱
几个容易出错的点:
- 不要只给父类加
callSuper = true—— 父类没有父类可调,该参数对父类无效 - 若子类重写了
canEqual()方法,需确保它允许与父类实例比较(否则super.equals()可能提前返回 false) - 使用
HashSet或HashMap时,若忘记callSuper = true,可能因hashCode不一致导致对象丢失或重复

















