# lombok-samples **Repository Path**: OlinOnee/lombok-samples ## Basic Information - **Project Name**: lombok-samples - **Description**: 关于lombok常用注解使用的案例。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-07-12 - **Last Updated**: 2022-07-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # lombok-samples #### 介绍 关于lombok常用注解使用的案例。 #### 1.先说结论 区别: `@NoArgsConstructor`:生成无参的构造方法。 `@AllArgsConstructor`:生成该类下全部属性的构造方法。 `@RequiredArgsConstructor`:生成该类下被 final 修饰或者 non-null 字段生成一个构造方法。 `@Data`:为所有字段生成 getter、toString 方法,non-transient 字段的 hashCode 和 equals 方法,非 non-final 字段的 setter 方法和无参构造方法。`@Data` 等价于 `@Getter` `@Setter` `@RequiredArgsConstructor` `@ToString` `@EqualsAndHashCode`注解合集。 `@UtilityClass`:标记当前类为 final 修饰,私有无参构造方法,所有方法、内部类、所有字段都标记为 static,不允许有参构造方法。 场景: 在springboot中,对于一个bean类,注入其他bean的时候,常见的是使用@Autowired,**实际上也可以使用构造函数注入**,这个时候就**可以使用@AllArgsConstructor或者@RequiredArgsConstructor来代替**。 --- #### 2.代码解析区别 @NoArgsConstructor 默认都知道。若不知道怎么查看java反编译字节码内容,可以看一下: Java 如何进行反编译生成.java文件(javap、jad下载安装使用) > 1. @AllArgsConstructor ```java @AllArgsConstructor public class AllArgsConstructorDemo { private String name; // 被final修饰 private final int age; @NonNull private String sex; } ``` 根据反编译查看代码: ```java import org.springframework.lang.NonNull; public class AllArgsConstructorDemo { private String name; private final int age; @NonNull private String sex; // 默认 只要是该类下的字段,无论什么修饰,都会被参与构造 public AllArgsConstructorDemo(String name, int age, @NonNull String sex) { if (sex == null) { throw new NullPointerException("sex is marked non-null but is null"); } else { this.name = name; this.age = age; this.sex = sex; } } } ``` 这是源码的英文解释: ![AllArgsConstructor注解源码](./doc/assets/AllArgsConstructor.png) > 2. @RequiredArgsConstructor ```java @RequiredArgsConstructor public class RequiredArgsConstructorDemo { private String name; // 被final修饰 private final int age; @NonNull private String sex; } ``` 反编译代码: ```java import org.springframework.lang.NonNull; public class RequiredArgsConstructorDemo { private String name; private final int age; @NonNull private String sex; // 只构造了有final或者no-null修饰的字段 public RequiredArgsConstructorDemo(int age, @NonNull String sex) { if (sex == null) { throw new NullPointerException("sex is marked non-null but is null"); } else { this.age = age; this.sex = sex; } } } ``` 这是源码的英文解释: ![RequiredArgsConstructor注解源码](./doc/assets/RequiredArgsConstructor.png) > 3. @Data ```java @Data public class DataDemo { private String name; private int age; private String sex; } ``` 反编译代码: ```java public class DataDemo { private String name; private int age; private String sex; public DataDemo() {} public String getName() {} public int getAge() {} public String getSex() {} public void setName(String name) {} public void setAge(int age) {} public void setSex(String sex) {} public boolean equals(Object o) {} protected boolean canEqual(Object other) {} public int hashCode() {} public String toString() {} } ``` 这是源码的英文解释: ![Data注解源码](./doc/assets/Data.png) > 4. @UtilityClass ```java @UtilityClass public class UtilityDemo { private String name; private int age; private String sex; } ``` 反编译代码: ```java public final class UtilityDemo { private static String name; private static int age; private static String sex; private UtilityDemo() { throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); } } ``` 这是源码的英文解释: ![UtilityClass注解源码](./doc/assets/UtilityClass.png) --- #### 3.场景使用—代替@Autowired注入bean对象 > 1. @AllArgsConstructor 根据上面看反编译代码可以得出:只要是类里面字段,都会被加入到构造函数里面,不管被什么修饰。 例子: ```java @Component public class BeanOne {} @Component public class BeanTwo {} @Component public class BeanThree {} @Component @AllArgsConstructor @ToString public class BeansDemo { // 注入三个bean对象,完全没有使用Autowired注解 private BeanOne beanOne; @NonNull private BeanTwo beanTwo; private final BeanThree beanThree; } // 这只是个测试类 @Component public class BeansRunner implements ApplicationRunner { @Autowired BeansDemo beansDemo; @Override public void run(ApplicationArguments args) throws Exception { System.out.println(beansDemo); } } ``` ![AllArgsConstructor注解运行结果](./doc/assets/AllArgsConstructor运行结果.png) 完完全全可以注入bean对象。 > 2. @RequiredArgsConstructor RequiredArgsConstructor:只会构造被final修饰或者no-null修饰的字段。 ```java @Component @RequiredArgsConstructor @ToString public class BeansDemo { private BeanOne beanOne; @NonNull private BeanTwo beanTwo; private final BeanThree beanThree; } ``` ![RequiredArgsConstructor注解运行结果](./doc/assets/RequiredArgsConstructor运行结果.png) 由图可以看出,**没有被修饰final或者no-null的属性无法被注入**,因此,**建议使用@RequiredArgsConstructor的时候,对需要的字段加上final修饰**。注:**强调 对需要的字段**,为什么要强调,请看下面的例子: > 3. @RequiredArgsConstructor 与 @AllArgsConstructor 在注入bean上的区别 根据上面两个例子,我们可以看出无论是那种方法都可以注入bean属性对象,只是@RequiredArgsConstructor 是针对有条件的,没有什么区别。 但如果是下面的需求呢: 在该类下,部分字段还需要使用@Value来注入值呢? ```java @Component @AllArgsConstructor @ToString public class BeansDemo { private BeanOne beanOne; @NonNull private BeanTwo beanTwo; private final BeanThree beanThree; @Value("${hello.name:world}") private String name; } // 先思考一下: // 一个bean如果使用构造函数进行bean属性注入,那么当然构造函数不能加上name。 // 因为加上,在创建ConstructorDemo该bean的时候,需要找类型为String,名字是name的bean对象,当然是不存在,必然会报错。 // 因此,当然不能使用@AllArgsConstructor了,只能使用@RequiredArgsConstructor ``` @AllArgsConstructor例子: ```java @Component @AllArgsConstructor @ToString public class BeansDemo { private BeanOne beanOne; @NonNull private BeanTwo beanTwo; private final BeanThree beanThree; // Parameter 3 of constructor in org.olinonee.framework.lombok.bean.BeansDemo required a bean of type 'java.lang.String' that could not be found. @Value("${hello.name:world}") private String name; } ``` ![AllArgsConstructor的Value注入运行结果](./doc/assets/AllArgsConstructor的Value注入运行结果.png) @RequiredArgsConstructor的例子 ```java @Component @RequiredArgsConstructor @ToString public class BeansDemo { private BeanOne beanOne; @NonNull private BeanTwo beanTwo; private final BeanThree beanThree; @Value("${hello.name:world}") private String name; } ``` ![RequiredArgsConstructor的Value注入运行结果](./doc/assets/RequiredArgsConstructor的Value注入运行结果.png) --- #### 4.总结 上面只是举例了代替`@Autowired`的例子,实际上在json转化为对象,以及在spring中从配置文件读取配置使用`@ConfigurationProperties`以及`@ConstructorBinding`的时候,都可以使用构造函数赋值,都可以用到上面的两个`@AllArgsConstructor`、`@RequiredArgsConstructor`。 具体:只要记得,哪些字段需要赋值,就把它列进构造方法的参数里面即可。 --- #### 5.参考 [@NoArgsConstructor、@AllArgsConstructor、@RequiredArgsConstructor的区别以及在springboot常用地方](https://www.ab62.cn/article/11041.html)