探究lombok-02-类继承
Java 8
org.springframework.boot 2.7.3
lombok 1.18.24
Eclipse Version: 2022-09 (4.25.0)
--ben发布于博客园
上一篇:探究lombok-01
https://www.cnblogs.com/luo630/p/16941897.html
注,本文测试结果的 LombokMain.java 的代码与上一篇相同。
0、序章
本文主要介绍类继承时使用lombok注解。涉及:ben发布于博客园
@Data、@Builder、@SuperBuilder
1、父子类都用@Data(可行)
孤使用频率最高的方式。ben发布于博客园
测试类:BaseDataVO、UserDataVO
// 1、BaseDataVO
import lombok.Data;
@Data
public class BaseDataVO {
private Integer supId;
private String supName;
}
// 2、UserDataVO
import java.util.Date;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
//@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class UserDataVO extends BaseDataVO {
private Integer id;
private String name;
private List<String> tags;
private Date createTime;
}
测试结果:和 前一篇 一直,多了几个成员方法
都用@Data的测试结果
测试:class=class com.lib.webdemo.vo2.BaseDataVO
prtClasses: length=0
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo2.BaseDataVO, 参数数量:0, modifiers=1
----
prtFields: length=2
字段:supId, type=class java.lang.Integer, modifiers=2
字段:supName, type=class java.lang.String, modifiers=2
----
prtMethods: length=8
方法名称:equals, 参数数量:1, modifiers=1
方法名称:toString, 参数数量:0, modifiers=1
方法名称:hashCode, 参数数量:0, modifiers=1
方法名称:setSupId, 参数数量:1, modifiers=1
方法名称:setSupName, 参数数量:1, modifiers=1
方法名称:getSupId, 参数数量:0, modifiers=1
方法名称:getSupName, 参数数量:0, modifiers=1
方法名称:canEqual, 参数数量:1, modifiers=4
测试:class=class com.lib.webdemo.vo2.UserDataVO
prtClasses: length=0
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo2.UserDataVO, 参数数量:0, modifiers=1
----
prtFields: length=4
字段:id, type=class java.lang.Integer, modifiers=2
字段:name, type=class java.lang.String, modifiers=2
字段:tags, type=interface java.util.List, modifiers=2
字段:createTime, type=class java.util.Date, modifiers=2
----
prtMethods: length=12
方法名称:equals, 参数数量:1, modifiers=1
方法名称:toString, 参数数量:0, modifiers=1
方法名称:hashCode, 参数数量:0, modifiers=1
方法名称:getName, 参数数量:0, modifiers=1
方法名称:getId, 参数数量:0, modifiers=1
方法名称:setName, 参数数量:1, modifiers=1
方法名称:setId, 参数数量:1, modifiers=1
方法名称:setTags, 参数数量:1, modifiers=1
方法名称:setCreateTime, 参数数量:1, modifiers=1
方法名称:canEqual, 参数数量:1, modifiers=4
方法名称:getTags, 参数数量:0, modifiers=1
方法名称:getCreateTime, 参数数量:0, modifiers=1
创建新对象及打印:在测试类 LombokMain 中添加下面的函数
private static void testDataVo() {
cs.accept("\n\n测试:testDataVo...");
BaseDataVO base = new BaseDataVO();
base.setSupId(999);
base.setSupName("super999");
cs.accept("BaseDataVO base=" + base);
UserDataVO user = new UserDataVO();
// 父
user.setSupId(888);
user.setSupName("super888");
// 子
user.setId(1);
user.setName("sub1");
user.setTags(new ArrayList<>());
user.setCreateTime(new Date());
cs.accept("UserDataVO user=" + user);
}
测试结果:
测试:testDataVo...
BaseDataVO base=BaseDataVO(supId=999, supName=super999)
UserDataVO user=UserDataVO(super=BaseDataVO(supId=888, supName=super888), id=1, name=sub1, tags=[], createTime=Fri Dec 02 19:21:12 CST 2022)
说明,UserDataVO 中的 super 为 父类的值,是因为 使用了注解 @ToString(callSuper = true) 才有的。ben发布于博客园
小结
常用方式。可行。要配合 @ToString(callSuper = true) 使用才能输出父类属性,或自己手写toString函数。
2、父子类都用@Builder(不可行)
此方式不可行。
测试类:BaseBuilderVO、UserBuilderVO
// 1、BaseBuilderVO
import lombok.Builder;
import lombok.ToString;
@Builder
@ToString
public class BaseBuilderVO {
private Integer supId;
private String supName;
}
// 2、UserBuilderVO
import java.util.Date;
import java.util.List;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Builder // 合理存在错误(1)
@ToString
public class UserBuilderVO extends BaseBuilderVO {
private Integer id;
private String name;
private List<String> tags;
private Date createTime;
}
错误(1):Eclipse提示如下
Implicit super constructor BaseBuilderVO() is undefined. Must explicitly invoke another constructor
BaseBuilderVO 没有默认构造函数 导致。ben发布于博客园
给 BaseBuilderVO 添加 @NoArgsConstructor 注解,此时,BaseBuilderVO 存在错误:
The constructor BaseBuilderVO(Integer, String) is undefined
再添加 @AllArgsConstructor 注解,BaseBuilderVO 未报错,但 UserBuilderVO 仍然报错:
UserBuilderVO 从错误 和之前一样。
这样看来,在 BaseBuilderVO 添加 @NoArgsConstructor 、 @AllArgsConstructor 无法解决问题(参考资料#2)。
进一步测试,在 UserBuilderVO 上添加 @NoArgsConstructor 、 @AllArgsConstructor 也解决不了报错。ben发布于博客园
参考资料#2 提到一种 手动创建构造函数的方式:试验未成功。
从 @Builder 注解的源码来看,它可以用在 类型、成员方法、构造器上面:
@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(SOURCE)
public @interface Builder {
//...
}
还需进一步探索。TODO
小结
放弃使用 @Builder 实现 类继承。ben发布于博客园
3、使用@SuperBuilder(可行)
按照 参考资料#2 的介绍,这是一个 试验性质 的注解。
import lombok.experimental.SuperBuilder;
包名里面有一个 experimental。
父类使用 @SuperBuilder
建立一个父类:BaseSuperBuilderVO
import lombok.experimental.SuperBuilder;
@SuperBuilder
@ToString
public class BaseSuperBuilderVO {
private Integer supId;
private String supName;
}
类检查结果:
测试:class=class com.lib.webdemo.vo2.BaseSuperBuilderVO
prtClasses: length=2
内部类: com.lib.webdemo.vo2.BaseSuperBuilderVO.BaseSuperBuilderVOBuilder, com.lib.webdemo.vo2.BaseSuperBuilderVO$BaseSuperBuilderVOBuilder, BaseSuperBuilderVOBuilder, com.lib.webdemo.vo2.BaseSuperBuilderVO$BaseSuperBuilderVOBuilder, modifiers=1033
内部类: com.lib.webdemo.vo2.BaseSuperBuilderVO.BaseSuperBuilderVOBuilderImpl, com.lib.webdemo.vo2.BaseSuperBuilderVO$BaseSuperBuilderVOBuilderImpl, BaseSuperBuilderVOBuilderImpl, com.lib.webdemo.vo2.BaseSuperBuilderVO$BaseSuperBuilderVOBuilderImpl, modifiers=26
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo2.BaseSuperBuilderVO, 参数数量:1, modifiers=4
----
prtFields: length=2
字段:supId, type=class java.lang.Integer, modifiers=2
字段:supName, type=class java.lang.String, modifiers=2
----
prtMethods: length=1
方法名称:builder, 参数数量:0, modifiers=9
这里出现了 两个内部类:BaseSuperBuilderVOBuilder(modifiers=1033)、BaseSuperBuilderVOBuilderImpl(modifiers=26)。
Eclipse的快捷键 Ctrl+Shift + T 可以搜搜到 这两个类:ben发布于博客园
BaseSuperBuilderVOBuilder 的 类分析测试结果:
测试:class=class com.lib.webdemo.vo2.BaseSuperBuilderVO$BaseSuperBuilderVOBuilder
prtClasses: length=0
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo2.BaseSuperBuilderVO$BaseSuperBuilderVOBuilder, 参数数量:0, modifiers=1
----
prtFields: length=2
字段:supId, type=class java.lang.Integer, modifiers=2
字段:supName, type=class java.lang.String, modifiers=2
----
prtMethods: length=7
方法名称:toString, 参数数量:0, modifiers=1
方法名称:supId, 参数数量:1, modifiers=1
方法名称:build, 参数数量:0, modifiers=1025
方法名称:supName, 参数数量:1, modifiers=1
方法名称:access$1, 参数数量:1, modifiers=4104
方法名称:access$0, 参数数量:1, modifiers=4104
方法名称:self, 参数数量:0, modifiers=1028
相比于使用@Builder,多了 access$1、access$0、self 3个方法。 ben发布于博客园
说明,BaseSuperBuilderVOBuilderImpl 是 private的,不做分析。
建立 BaseSuperBuilderVO 对象:
private static void testCreateBaseSuperBuilderVO() {
BaseSuperBuilderVO base = BaseSuperBuilderVO.builder()
.supId(999)
.supName("super999")
.build();
cs.accept("BaseSuperBuilderVO base=" + base);
}
测试结果:
BaseSuperBuilderVO base=BaseSuperBuilderVO(supId=999, supName=super999)
子类使用 @SuperBuilder
新建子类 UserSuperBuilderVO:
import java.util.Date;
import java.util.List;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
@SuperBuilder
@ToString(callSuper = true)
public class UserSuperBuilderVO extends BaseSuperBuilderVO {
private Integer id;
private String name;
private List<String> tags;
private Date createTime;
}
分析类 UserSuperBuilderVO、UserSuperBuilderVOBuilder 的测试结果:ben发布于博客园
测试:class=class com.lib.webdemo.vo2.UserSuperBuilderVO
prtClasses: length=2
内部类: com.lib.webdemo.vo2.UserSuperBuilderVO.UserSuperBuilderVOBuilder, com.lib.webdemo.vo2.UserSuperBuilderVO$UserSuperBuilderVOBuilder, UserSuperBuilderVOBuilder, com.lib.webdemo.vo2.UserSuperBuilderVO$UserSuperBuilderVOBuilder, modifiers=1033
内部类: com.lib.webdemo.vo2.UserSuperBuilderVO.UserSuperBuilderVOBuilderImpl, com.lib.webdemo.vo2.UserSuperBuilderVO$UserSuperBuilderVOBuilderImpl, UserSuperBuilderVOBuilderImpl, com.lib.webdemo.vo2.UserSuperBuilderVO$UserSuperBuilderVOBuilderImpl, modifiers=26
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo2.UserSuperBuilderVO, 参数数量:1, modifiers=4
----
prtFields: length=4
字段:id, type=class java.lang.Integer, modifiers=2
字段:name, type=class java.lang.String, modifiers=2
字段:tags, type=interface java.util.List, modifiers=2
字段:createTime, type=class java.util.Date, modifiers=2
----
prtMethods: length=2
方法名称:toString, 参数数量:0, modifiers=1
方法名称:builder, 参数数量:0, modifiers=9
测试:class=class com.lib.webdemo.vo2.UserSuperBuilderVO$UserSuperBuilderVOBuilder
prtClasses: length=0
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo2.UserSuperBuilderVO$UserSuperBuilderVOBuilder, 参数数量:0, modifiers=1
----
prtFields: length=4
字段:id, type=class java.lang.Integer, modifiers=2
字段:name, type=class java.lang.String, modifiers=2
字段:tags, type=interface java.util.List, modifiers=2
字段:createTime, type=class java.util.Date, modifiers=2
----
prtMethods: length=13
方法名称:name, 参数数量:1, modifiers=1
方法名称:toString, 参数数量:0, modifiers=1
方法名称:id, 参数数量:1, modifiers=1
方法名称:tags, 参数数量:1, modifiers=1
方法名称:createTime, 参数数量:1, modifiers=1
方法名称:build, 参数数量:0, modifiers=1025
方法名称:build, 参数数量:0, modifiers=4161
方法名称:access$3, 参数数量:1, modifiers=4104
方法名称:access$5, 参数数量:1, modifiers=4104
方法名称:access$2, 参数数量:1, modifiers=4104
方法名称:access$4, 参数数量:1, modifiers=4104
方法名称:self, 参数数量:0, modifiers=4164
方法名称:self, 参数数量:0, modifiers=1028
UserSuperBuilderVO多了两个内部类,
UserSuperBuilderVOBuilder有13个方法,其中access$2~5(access$0~1 在 父类中),两个build,两个self。
创建子类对象,可以看到 父类的属性也在了:supId、supName
小结
@SuperBuilder 用在了 父类、子类上,可以成功创建父子类对象。
不过,这个功能属于试验性质的,暂无更多精时去探究。ben发布于博客园
4、父类用@Data、子类用@Builder(可行)
新建父类BaseData2VO、子类UserBuilder2VO:
// 1、BaseData2VO
import lombok.Data;
@Data
public class BaseData2VO {
private Integer supId;
private String supName;
}
// 2、UserBuilder2VO
import java.util.Date;
import java.util.List;
import lombok.Builder;
import lombok.ToString;
@Builder
@ToString(callSuper = true)
public class UserBuilder2VO extends BaseData2VO {
private Integer id;
private String name;
private List<String> tags;
private Date createTime;
}
执行 子类UserBuilder2VO 的类分析:
测试:class=class com.lib.webdemo.vo2.UserBuilder2VO
prtClasses: length=1
内部类: com.lib.webdemo.vo2.UserBuilder2VO.UserBuilder2VOBuilder, com.lib.webdemo.vo2.UserBuilder2VO$UserBuilder2VOBuilder, UserBuilder2VOBuilder, com.lib.webdemo.vo2.UserBuilder2VO$UserBuilder2VOBuilder, modifiers=9
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo2.UserBuilder2VO, 参数数量:4, modifiers=0
----
prtFields: length=4
字段:id, type=class java.lang.Integer, modifiers=2
字段:name, type=class java.lang.String, modifiers=2
字段:tags, type=interface java.util.List, modifiers=2
字段:createTime, type=class java.util.Date, modifiers=2
----
prtMethods: length=2
方法名称:toString, 参数数量:0, modifiers=1
方法名称:builder, 参数数量:0, modifiers=9
注意,这里的 UserBuilder2VOBuilder 不能执行上面的类分析,和单独使用 @Builder 注解类不同。ben发布于博客园
创建UserBuilder2VO对象:父类的属性需要使用 setter 方法设置
private static void testCreateDataBuilderVO() {
cs.accept("\n\n测试:testCreateDataBuilderVO...");
UserBuilder2VO user = UserBuilder2VO.builder()
// 子
.id(2)
.name("sub2")
.tags(new ArrayList<>())
.createTime(new Date())
.build();
// 父
user.setSupId(999);
user.setSupName("super999");
cs.accept("UserBuilder2VO user=" + user);
}
测试结果:
测试:testCreateDataBuilderVO...
UserBuilder2VO user=UserBuilder2VO(super=BaseData2VO(supId=999, supName=super999), id=2, name=sub2, tags=[], createTime=Fri Dec 02 20:38:49 CST 2022)
小结
可以用这种方式,只不过父类属性需要使用 setter方法设置。ben发布于博客园
参考资料
1、Lombok 中@Builder 的使用
https://www.cnblogs.com/minmin123/p/14368725.html
2、java Lombok下解决@Builder继承解决方法(@SuperBuilder)
http://www.manongjc.com/detail/28-quhwksxdbgivhva.html
ben发布于博客园