在使用 Lombok 时,@Builder 提供了非常优雅的方式构建对象。但当涉及类继承结构时,很多开发者会发现一个问题:
子类使用
@Builder时,无法设置父类中的字段。
本文将详解为什么会这样,并介绍几种解决方案,特别推荐使用 @SuperBuilder 来优雅支持继承下的对象构造。
问题重现:@Builder 无法处理父类字段
来看一个简单的例子:
@Getter
public class Parent {
private String parentField;
}
@Builder
@Getter
public class Child extends Parent {
private String childField;
}
尝试构造:
Child child = Child.builder()
.parentField("parent") // 编译错误:找不到 parentField()
.childField("child")
.build();
结果发现:父类字段 parentField 无法通过 builder 设置。
原因是:@Builder 默认只处理当前类的字段,不会考虑继承的父类字段。
✅ 正确做法:使用 @SuperBuilder
为了解决继承中的 builder 问题,Lombok 提供了 @SuperBuilder 注解。它是 @Builder 的增强版本,专门用于支持类继承结构下的构造。
示例代码
父类:
import lombok.experimental.SuperBuilder;
import lombok.Getter;
@SuperBuilder
@Getter
public class Parent {
private String parentField;
}
子类:
import lombok.experimental.SuperBuilder;
import lombok.Getter;
import lombok.ToString;
@SuperBuilder
@Getter
@ToString(callSuper = true)
public class Child extends Parent {
private String childField;
}
构造示例:
Child child = Child.builder()
.parentField("Hello Parent")
.childField("Hello Child")
.build();
System.out.println(child);
输出结果:
Child(parentField=Hello Parent, childField=Hello Child)
特点总结
@SuperBuilder支持链式构造父类字段;- 父类和子类都需使用
@SuperBuilder; - 可搭配
toBuilder = true实现对象复制修改。
⚠️ 其他方案(了解即可)
手动传递构造器参数(不推荐)
如果你坚持使用 @Builder,可以手动在子类构造器中接收并传递父类字段:
@Builder
public class Child extends Parent {
private String childField;
public Child(String parentField, String childField) {
super(parentField);
this.childField = childField;
}
}
这虽然可以实现目标,但会丢失 Lombok 的自动化构造优势,维护成本高,不推荐使用。
✅ 最佳实践建议
| 需求 | 推荐方案 |
|---|---|
| 普通类构造 | @Builder |
| 父子类都需构造字段 | @SuperBuilder |
| 搭配 Jackson/JPA | 手动构造器或谨慎使用 @SuperBuilder(需测试兼容性) |
| 有复制/修改需求 | @SuperBuilder(toBuilder = true) |
结语
Lombok 的 @Builder 在平铺结构中非常方便,但面对继承结构时存在局限。此时使用 @SuperBuilder 是更加现代和优雅的方式,能让你的构造代码保持清晰和强大。
