c++ 子类复制父类_Lombok 子类如何使用 @Builder

本文介绍了如何使用Lombok的@SuperBuilder解决子类在构建时无法初始化父类属性的问题。通过@SuperBuilder和toBuilder参数,可以方便地在子类中构建包含父类属性的对象,避免了手动编写构造方法的繁琐。同时,文章提到了Lombok的一个已知bug,即在某些版本中不支持特定名称的类,但已在后续版本中修复。
摘要由CSDN通过智能技术生成

d06cb4317d71c469594bd69f3b98222a.gif

作者:jitwxs

https://jitwxs.cn/54621f54.html

一、前言

业务开发中,子类父类还算是经常用到,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 仅可以初始化自己的属性,父类属性无法初始化。

fd3cc81d772d8bf26a7221d3f11172bc.png

二、解决:构造方法

查阅网络后,一种解决方法是利用构造方法:

  • 父类生成全参构造方法
  • 子类手动声明全参构造方法
  • 将子类 @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 时,使用上文的例子,你就会发现竟然无法通过编译。

978af9a8f5d4230fd4f5300828b62d60.png

实际的原因是不支持用 B 来命名类,简直是吐出一口老血,好在升级到 v1.18.12 版本后就修复了这个问题,可能这就是给不规范命名的人埋的坑吧,哈哈。

END

推荐好文

强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

分享一套基于SpringBoot和Vue的企业级中后台开源项目,代码很规范!

能挣钱的,开源 SpringBoot 商城系统,功能超全,超漂亮!

b9ad637970c71d21b8c85f2fbdfe3604.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值