首页 > Python资料 博客日记

@Build 与 @SuperBuild 的区别

2025-01-16 18:30:06Python资料围观12

这篇文章介绍了@Build 与 @SuperBuild 的区别,分享给大家做个参考,收藏Python资料网收获更多编程知识

优质博文:IT-BLOG-CN

一、@Builder

@Builderlombok中的注解。可以使用builder()构造的Person.PersonBuilder对象进行链式调用,给所有属性依次赋值。

    Person person1 = Person.builder()
            .name("张三")
            .age(20)
            .build();
    System.out.println(person1);                // Person(name=张三, age=20)
    System.out.println(Person.builder());       // Person.PersonBuilder(name=null, age=null)

文档中给了案例,在实体类上添加@Builder后,实体类会被改造成如下的结构:

Before:
  @Builder
  class Example<T> {
  	private T foo;
  	private final String bar;
  }
  
After:
  class Example<T> {
  	private T foo;
  	private final String bar;
  	
  	// 私有的全参数构造函数
  	private Example(T foo, String bar) {
  		this.foo = foo;
  		this.bar = bar;
  	}
  	
    // 返回一个重新构建的Builder对象
  	public static <T> ExampleBuilder<T> builder() {
  		return new ExampleBuilder<T>();
  	}
  	
    // 没一次都是放回一个构建后的对象
  	public static class ExampleBuilder<T> {
  		private T foo;
  		private String bar;
  		
  		private ExampleBuilder() {}
  		
  		public ExampleBuilder foo(T foo) {
  			this.foo = foo;
  			return this;
  		}
  		
  		public ExampleBuilder bar(String bar) {
  			this.bar = bar;
  			return this;
  		}
  		
  		@java.lang.Override public String toString() {
  			return "ExampleBuilder(foo = " + foo + ", bar = " + bar + ")";
  		}
  		
  		public Example build() {
  			return new Example(foo, bar);
  		}
  	}
  }

Builder注解开发的源代码:

@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(SOURCE)
public @interface Builder {

    // 内部注解 Default
	@Target(FIELD) // @Target: 指定这个注解可以应用的程序元素类型。
	@Retention(SOURCE)// @Retention: 指定这个注解的保留策略。SOURCE: 注解只在源代码中保留,编译时会被丢弃。
	public @interface Default {}

    // Builder 注解的属性
	String builderMethodName() default "builder"; // 定义生成的 builder 方法的名称,默认为 "builder"。

	String buildMethodName() default "build"; // 定义生成的 build 方法的名称,默认为 "build"。
	
	String builderClassName() default ""; // 定义生成的 builder 类的名称,默认为空字符串。

	boolean toBuilder() default false; // 指定是否生成一个 toBuilder 方法,默认为 false。

	AccessLevel access() default lombok.AccessLevel.PUBLIC; // : 定义生成的 builder 方法的访问级别,默认为 lombok.AccessLevel.PUBLIC。

	String setterPrefix() default ""; // 定义生成的 setter 方法的前缀,默认为空字符串。
	
    // 内部注解 ObtainVia
	@Target({FIELD, PARAMETER})
	@Retention(SOURCE)
	public @interface ObtainVia {

		String field() default "";

		String method() default "";
		
		boolean isStatic() default false;
	}
}

@Builder.Default:使用@Builder.Default设置默认值,构建对象时可以不用调用name()方法。(调用后会覆盖默认值)

@Builder.Default
private String name = "zhangsan";

二、为什么要使用 @SuperBuilder

在涉及到继承相关的子父类字段时,如果使用@Builder会出现编译错误:

// 第一个类
@Builder  
public class Person{  
    private String name;  
}

// 第二个类
@Builder  
public class Man extends Person{  
    private String career;  
}

编译报错:

无法将Person中的构造器 Person应用到给定类型;
  需要: java.lang.String
  找到: 没有参数
  原因: 实际参数列表和形式参数列表长度不同

Man构建的时候会去构建子类Person,但是Person由于加了@Builder,没有无参构建函数;

public class Man extends Person {  
    private String career;  
  
    Man(final String career) {  
        this.career = career;  
    }  
  
    public static ManBuilder builder() {  
        return new ManBuilder();  
    }  
  
    public static class ManBuilder {  
        private String career;  
  
        ManBuilder() {  
        }  
  
        public ManBuilder career(final String career) {  
            this.career = career;  
            return this;  
        }  
  
        public Man build() {  
            return new Man(this.career);  
        }  
  
        public String toString() {  
            return "Man.ManBuilder(career=" + this.career + ")";  
        }  
    }  
}

既然是没有无参构造函数,那么就在子类上添加无参构造函数@NoArgsConstructor

但是idea提示错误,Lombok @Builder needs a proper constructor for this class,那么再加上@AllArgsConstructor,成功消除报错,但是编译报错,提示:

java: Man中的builder()无法覆盖Person中的builder()
返回类型Man.ManBuilderPerson.PersonBuilder不兼容

该错误是因为Man类中的builder()方法试图重写Person类中的builder()方法,但是返回类型不匹配导致的。Person类的builder()方法返回的是PersonBuilder类型的对象。Man类继承自Person,但其builder()方法返回的是ManBuilder类型的对象。

Java中,子类的方法如果要重写父类的方法,那么子类方法的返回类型必须是父类方法返回类型的子类型或者相同类型。这里ManBuilderPersonBuilder是两个独立的类型,不是继承关系,因此不符合Java的重写规则。所以就需要使用到@SuperBuilder

三、@SuperBuilder

@Builder注解无法解析父类的属性,而@SuperBuilder可以读取父类的属性。使用时需要在子类和父类上都加上这个注解。

@SuperBuilder
public class Male extends Person{
}

@SuperBuilder
public class Person {
    @Builder.Default
    private String name = "zhangsan";

    private Integer age;

    @Singular("skillList")
    private List<String> skillList;
}

@SuperBuilder(toBuilder=true):使用@SuperBuilder(toBuilder=true)可以使用已有的对象构建新的对象,旧对象的属性值会被保留和覆盖。注意: 子类和父类都需要加上toBuilder=true

Male man = Male.builder()
        .name("张三")
        .age(20)
        .build();

Male man2 = man.toBuilder()
        .age(30)
        .build();

四、@SuperBuilder 不能与 @NoArgsConstructor 直接共存

有时我们需要@NoArgsConstructor无参构造函数,但如果直接与@SuperBuilder一起使用,会遇到编译冲突,导致构造器生成失败。可以借助@NoArgsConstructorforce属性,强制生成无参构造函数:这样Lombok会生成无参构造器,同时支持@SuperBuilder

@NoArgsConstructor(force = true)
@SuperBuilder
public class Example {
    private final String field;
}

版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐