為了更簡(jiǎn)潔的構(gòu)造bean對(duì)象,使用注解@Builder,然而發(fā)現(xiàn),通過(guò)builder生成的bean對(duì)象,字段默認(rèn)值沒(méi)了(備注:日常開發(fā)中,bean 的成員變量盡量使用封裝對(duì)象,以及盡量不要有默認(rèn)值),但是通過(guò)new 得到的對(duì)象,字段默認(rèn)值存在。
問(wèn)題偽代碼如下:
/** * @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);}}執(zhí)行結(jié)果如下:UserChildren(name=七夜, age=null)UserChildren(name=null, age=null)
針對(duì)lombok注解問(wèn)題的排查,最簡(jiǎn)單的方式就是直接查看編譯之后的代碼。反編譯后的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 + “)”; } }}
通過(guò)查看編譯之后的代碼,可以看到,使用@Builder注解之后,lombok會(huì)生成一個(gè)UserChildrenBuilder的靜態(tài)內(nèi)部類,這個(gè)類包含了UserChildren的成員變量,但是包含的成員變量中,name字段的初始值沒(méi)了,當(dāng)我們使用UserChildren.builder().build()來(lái)構(gòu)造bean時(shí),代碼內(nèi)部先生成一個(gè)UserChildrenBuilder的對(duì)象,然后對(duì)這個(gè)對(duì)象進(jìn)行賦值,最后調(diào)用UserChildren的全參構(gòu)造函數(shù),生成UserChildren對(duì)象。就像一個(gè)代理一樣!
因此:
使用new 對(duì)象時(shí),沒(méi)有使用到UserChildrenBuilder,因此name字段的初始值保留了。
使用builder構(gòu)造對(duì)象時(shí),UserChildrenBuilder的name字段沒(méi)有了初始值,生成的對(duì)象,name字段自然就沒(méi)值了。