点击上方 "编程技术圈"关注, 星标或置顶一起成长
后台回复“大礼包”有惊喜礼包!
每日英文
Miracles sometimes occur, but you have to work terribly for them.
奇迹有时候是会发生的,但是你得为之拼命的努力。
每日掏心话
无须匆忙,该来的总是会来,在对的时间,对的人,因为对的理由。
来自:jitwxs | 责编:乐乐
链接:jitwxs.cn/54621f54.html
编程技术圈(ID:study_tech)第 1117 次推文
往日回顾:程序员真的是太太太太太太太太难了!
正文
一、前言
业务开发中,子类父类还算是经常用到,Lombok 的 @builder 提供的链式调用帮助我们更轻松的创建对象。但是实验后却发现子类的 @Builder 是不会包含父类的属性。
假设存在父类 A:
`@Data
@Builder
public class A {
private String aName;
private String aAge;
}
`
存在子类 B:
`@Builder
@Data
@EqualsAndHashCode(callSuper = true)
public class B extends A {
private String bName;
private String bAge;
}
`
使用 builder 进行初始化时,类 A 可以正常创建,类 B 仅可以初始化自己的属性,父类属性无法初始化。
二、解决:构造方法
查阅网络后,一种解决方法是利用构造方法:
父类生成全参构造方法
子类手动声明全参构造方法
将子类 @builder 注解移动全参构造方法上,并设置 builderMethodName
`@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class A {
private String aName;
private String aAge;
}
`
`@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class B extends A {
private String bName;
private String bAge;
@Builder(builderMethodName = "childBuilder")
public B(String aName, String aAge, String bName, String bAge) {
super(aName, aAge);
this.bName = bName;
this.bAge = bAge;
}
}
`
修改 Main 方法如下:
`public class BuilderMain {
public static void main(String[] args) {
A xxx = A.builder()
.aName("xxx")
.aAge("111")
.build();
B yyy = B.childBuilder()
.aName("xxx")
.aAge("111")
.bName("yyy")
.bAge("222")
.build();
System.out.println(xxx);
System.out.println(yyy);
}
}
`
代码运行后,能得到正确结果:
A(aName=xxx, aAge=111) B(super=A(aName=xxx, aAge=111), bName=yyy, bAge=222)
但是这种方式弊端也很明显:
子类调用父类的全参构造,当父类参数数量、顺序调整时,子类也需要同步调整。
如果父类参数过多,构造方法十分不优雅。
三、解决:SuperBuilder
Lombok 自 v1.18.2 开始,为了解决这个问题,引入了 @SuperBuilder 注解,使用该注解,就可以很容易解决这个问题。在公众号顶级架构师后台回复“架构整洁”,获取一份惊喜礼包。
修改代码如下:
`@Data
@SuperBuilder
public class A {
private String aName;
private String aAge;
}
`
`@SuperBuilder
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class B extends A {
private String bName;
private String bAge;
}
`
Main 方法保持不变,代码运行后,能得到正确结果:
A(aName=xxx, aAge=111) B(super=A(aName=xxx, aAge=111), bName=yyy, bAge=222)
另外自 v1.18.4 也给 SuperBuilder 引入了toBuilder 参数,可以很方便的进行浅拷贝对象,效率虽然比手动 builder 慢一点,但也算是挺快的。
`@Data
@SuperBuilder(toBuilder = true)
public class A {
private String aName;
private String aAge;
}
`
给 B 加入属性 C,测试对象拷贝:
`@SuperBuilder(toBuilder = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class B extends A {
private String bName;
private String bAge;
private C c;
}
`
~
@AllArgsConstructor public class C { private String name; }
输出结果如下:
`public class BuilderMain {
public static void main(String[] args) {
B b = B.builder()
.aName("xxx")
.aAge("111")
.bName("yyy")
.bAge("222")
.c(new C("zhangsan"))
.build();
System.out.println(b);
System.out.println(b.toBuilder().build());
}
}
`
B(super=A(aName=xxx, aAge=111), bName=yyy, bAge=222, c=com.github.jitwxs.demo.builder.C@52cc8049) B(super=A(aName=xxx, aAge=111), bName=yyy, bAge=222, c=com.github.jitwxs.demo.builder.C@52cc8049)
四、彩蛋
由于 @SuperBuilder 刚引入不久,所以还是有一些 BUG 的,比如当你的 SpringBoot 版本为 2.2.3.RELEASE 时,或者你的 Lombok 版本低于 v1.18.12 时,使用上文的例子,你就会发现竟然无法通过编译。
实际的原因是不支持用 B 来命名类,简直是吐出一口老血,好在升级到 v1.18.12 版本后就修复了这个问题,可能这就是给不规范命名的人埋的坑吧,哈哈。
PS: 欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。
版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!
猜你还想看
又一起“删库”跑路:链家程序员怒删公司 9TB 数据,被判 7 年!网友:真惨~
BAT等大厂Java面试经验总结
别找了,想获取 Java大厂面试题学习资料
扫下方二维码回复「手册」就好了
**嘿,你在看吗?**********
本文分享自微信公众号 - 程序员小乐(study_tech)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。