为了更简洁的构造bean对象,使用注解@Builder,然而发现,通过builder生成的bean对象,字段默认值没了(备注:日常开发中,bean 的成员变量尽量使用封装对象,以及尽量不要有默认值),但是通过new 得到的对象,字段默认值存在。
问题伪代码如下:
/** * @description: 用户父类 * @author: lyl * @create: 2022-06-01 14:42:27 **/@Datapublic class UserParent { /** * id */ private String id;}@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class UserChildren extends UserParent{ /** * 姓名 */ private String name = “七夜”; /** * 年龄 */ private Integer age;}@SpringBootTestclass CodeTestApplicationTests {@Testvoid contextLoads() {UserChildren user1 = new UserChildren();System.out.println(user1);UserChildren user2 = UserChildren.builder().build();System.out.println(user2);}}执行结果如下:UserChildren(name=七夜, age=null)UserChildren(name=null, age=null)
针对lombok注解问题的排查,最简单的方式就是直接查看编译之后的代码。反编译后的UserCildren.class如下:
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//package com.yalin.code.vo;public class UserChildren extends UserParent { private String name = “七夜”; private Integer age; public static UserChildrenBuilder builder() { return new UserChildrenBuilder(); } public String getName() { return this.name; } public Integer getAge() { return this.age; } public void setName(final String name) { this.name = name; } public void setAge(final Integer age) { this.age = age; } public boolean equals(final Object o) { if (o == this) { return true; } else if (!(o instanceof UserChildren)) { return false; } else { UserChildren other = (UserChildren)o; if (!other.canEqual(this)) { return false; } else { Object this$age = this.getAge(); Object other$age = other.getAge(); if (this$age == null) { if (other$age != null) { return false; } } else if (!this$age.equals(other$age)) { return false; } Object this$name = this.getName(); Object other$name = other.getName(); if (this$name == null) { if (other$name != null) { return false; } } else if (!this$name.equals(other$name)) { return false; } return true; } } } protected boolean canEqual(final Object other) { return other instanceof UserChildren; } public int hashCode() { int PRIME = true; int result = 1; Object $age = this.getAge(); result = result * 59 + ($age == null ? 43 : $age.hashCode()); Object $name = this.getName(); result = result * 59 + ($name == null ? 43 : $name.hashCode()); return result; } public String toString() { String var10000 = this.getName(); return “UserChildren(name=” + var10000 + “, age=” + this.getAge() + “)”; } public UserChildren() { } public UserChildren(final String name, final Integer age) { this.name = name; this.age = age; } public static class UserChildrenBuilder { private String name; private Integer age; UserChildrenBuilder() { } public UserChildrenBuilder name(final String name) { this.name = name; return this; } public UserChildrenBuilder age(final Integer age) { this.age = age; return this; } public UserChildren build() { return new UserChildren(this.name, this.age); } public String toString() { return “UserChildren.UserChildrenBuilder(name=” + this.name + “, age=” + this.age + “)”; } }}
通过查看编译之后的代码,可以看到,使用@Builder注解之后,lombok会生成一个UserChildrenBuilder的静态内部类,这个类包含了UserChildren的成员变量,但是包含的成员变量中,name字段的初始值没了,当我们使用UserChildren.builder().build()来构造bean时,代码内部先生成一个UserChildrenBuilder的对象,然后对这个对象进行赋值,最后调用UserChildren的全参构造函数,生成UserChildren对象。就像一个代理一样!
因此:
使用new 对象时,没有使用到UserChildrenBuilder,因此name字段的初始值保留了。
使用builder构造对象时,UserChildrenBuilder的name字段没有了初始值,生成的对象,name字段自然就没值了。