为什么要在实体上同时使用@AllArgsConstructor 和@NoArgsConstructor?
Why to use @AllArgsConstructor and @NoArgsConstructor together over an Entity?
我在 IntelliJ 中看到 Spring Boot 应用程序的多个在线代码,许多代码同时使用 @AllArgsConstructor
和 @NoArgsConstructor
,两者都是构造函数,但每个的目的不同-
@AllArgsConstructor
为带注释的 class 中的每个字段生成一个需要参数的构造函数
@NoArgsConstructor
生成一个没有参数的构造函数
那为什么我们要在同一个实体上同时使用这两种方法?在这种情况下它们是如何工作的?
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Entity
public class Product {
@Id
private int id;
private String name;
private String type;
}
JPA specification requires that all persistent classes (@Entity
) have a no-arg constructor, public or protected. (note that this is not necessarily true when dealing with some implementation like Hibernate, see this answer).
这是必需的,因为 JPA 使用默认构造函数方法通过反射 API 创建 bean class。实际上,如果您的 class 包含许多构造函数,那么 JPA 将不知道调用哪个构造函数,这就是它使用反射通过其无参数构造函数实例化 class 的原因:
Product.class.newInstance();
相当于 new Product()
(Product.class
是 class 文字 ,如果 class 在 class 路径中找不到),然后,一旦实例化,使用字段设置器来处理它。
然后,在Java中,自动为class生成默认构造函数(无参数构造函数),除非您定义其他构造函数(仅当您不提供任何其他构造函数时才会这样做)构造函数)。
因此,因为编译器会在没有定义其他构造函数时自动创建默认的无参数构造函数,所以如果框架需要,只有 class 定义构造函数的 es 还必须包含无参数构造函数(此处为 JPA ).这就是为什么如果添加 @AllArgsConstructor
注释,则需要添加 @NoArgsConstructor
注释。
另请注意,您正在使用 @Data
,它捆绑了 @RequiredArgsConstructor
的功能,它将为所有 final
或 @NonNull
注释字段生成一个构造函数(请参阅龙目岛 documentation)。因此,由于您仅使用非最终可为空的字段,因此即使您不添加 @NoArgsConstructor
注释,它也可能会生成一个空的构造函数。虽然我没有测试最后一种情况,但我知道它在直接对非最终可为空字段使用 @RequiredArgsConstructor
时会生成一个空构造函数,但我不知道在使用 @Data
时是否同样有效。
@Data
还捆绑了 @ToString
,因此您无需再次添加。
如果我不需要所有捆绑的注释,我个人不喜欢使用 @Data
,所以我通常只使用 :
@Entity
@Getter
@Setter
@EqualsAndHashCode
public class Product {
@Id
private int id;
private String name;
private String type;
}
因为我通常不使用 toString()
也不使用参数化构造函数。它可能更冗长但对我来说更有意义。
这些是来自 Lombok 的注释。要理解为什么需要它,您必须了解事物的内部运作方式。
JPA 说
它的规范说“JPA 规范要求所有持久性 classes 都有一个无参数的构造函数。这个构造函数可以是 public 或受保护的。因为编译器会自动创建一个默认的无- arg 构造函数当没有定义其他构造函数时,只有 class 定义构造函数的 es 还必须包含无参数构造函数。"
为了进一步理解,当它使用反射创建实体时,它使用 Class.newInstance() 方法,该方法需要 无参数构造函数 创建实例。
Spring 使用的最常见的依赖注入类型是
- 基于构造函数的注入
- Setter 基于注入
基于构造函数的注入: 当您通过传递所有参数创建对象时,您基本上使用了构造函数注入。当我们拥有所有参数值并且我们想要创建一个所有值都已初始化的对象时,应该这样做。(@AllArgsConstructor)
基于 Setter 的注入: 我们首先创建一个对象(不使用 arg-constructor),然后稍后使用 setter 更新依赖项或值s.(@NoArgsConstructor)
构造函数注入和 setter 注入之间有许多关键区别。
部分依赖: 可以使用 setter 注入,但不能通过构造函数注入。假设a中有3个属性
class,具有 3 个参数构造函数和 setters 方法。在这种情况下,如果
你只想传递一个 属性 的信息,可以通过
setter 仅方法。
覆盖: Setter注入覆盖构造函数注入。如果我们同时使用构造函数和 setter 注入,IOC 容器将
使用 setter 注入。
变化:我们可以通过setter注入轻松改变值。它不会像构造函数那样总是创建一个新的 bean 实例。所以 setter
注入比构造函数注入灵活。
我在 IntelliJ 中看到 Spring Boot 应用程序的多个在线代码,许多代码同时使用 @AllArgsConstructor
和 @NoArgsConstructor
,两者都是构造函数,但每个的目的不同-
@AllArgsConstructor
为带注释的 class 中的每个字段生成一个需要参数的构造函数
@NoArgsConstructor
生成一个没有参数的构造函数
那为什么我们要在同一个实体上同时使用这两种方法?在这种情况下它们是如何工作的?
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Entity
public class Product {
@Id
private int id;
private String name;
private String type;
}
JPA specification requires that all persistent classes (@Entity
) have a no-arg constructor, public or protected. (note that this is not necessarily true when dealing with some implementation like Hibernate, see this answer).
这是必需的,因为 JPA 使用默认构造函数方法通过反射 API 创建 bean class。实际上,如果您的 class 包含许多构造函数,那么 JPA 将不知道调用哪个构造函数,这就是它使用反射通过其无参数构造函数实例化 class 的原因:
Product.class.newInstance();
相当于 new Product()
(Product.class
是 class 文字 ,如果 class 在 class 路径中找不到),然后,一旦实例化,使用字段设置器来处理它。
然后,在Java中,自动为class生成默认构造函数(无参数构造函数),除非您定义其他构造函数(仅当您不提供任何其他构造函数时才会这样做)构造函数)。
因此,因为编译器会在没有定义其他构造函数时自动创建默认的无参数构造函数,所以如果框架需要,只有 class 定义构造函数的 es 还必须包含无参数构造函数(此处为 JPA ).这就是为什么如果添加 @AllArgsConstructor
注释,则需要添加 @NoArgsConstructor
注释。
另请注意,您正在使用 @Data
,它捆绑了 @RequiredArgsConstructor
的功能,它将为所有 final
或 @NonNull
注释字段生成一个构造函数(请参阅龙目岛 documentation)。因此,由于您仅使用非最终可为空的字段,因此即使您不添加 @NoArgsConstructor
注释,它也可能会生成一个空的构造函数。虽然我没有测试最后一种情况,但我知道它在直接对非最终可为空字段使用 @RequiredArgsConstructor
时会生成一个空构造函数,但我不知道在使用 @Data
时是否同样有效。
@Data
还捆绑了 @ToString
,因此您无需再次添加。
如果我不需要所有捆绑的注释,我个人不喜欢使用 @Data
,所以我通常只使用 :
@Entity
@Getter
@Setter
@EqualsAndHashCode
public class Product {
@Id
private int id;
private String name;
private String type;
}
因为我通常不使用 toString()
也不使用参数化构造函数。它可能更冗长但对我来说更有意义。
这些是来自 Lombok 的注释。要理解为什么需要它,您必须了解事物的内部运作方式。
JPA 说
它的规范说“JPA 规范要求所有持久性 classes 都有一个无参数的构造函数。这个构造函数可以是 public 或受保护的。因为编译器会自动创建一个默认的无- arg 构造函数当没有定义其他构造函数时,只有 class 定义构造函数的 es 还必须包含无参数构造函数。"
为了进一步理解,当它使用反射创建实体时,它使用 Class.newInstance() 方法,该方法需要 无参数构造函数 创建实例。
Spring 使用的最常见的依赖注入类型是
- 基于构造函数的注入
- Setter 基于注入
基于构造函数的注入: 当您通过传递所有参数创建对象时,您基本上使用了构造函数注入。当我们拥有所有参数值并且我们想要创建一个所有值都已初始化的对象时,应该这样做。(@AllArgsConstructor)
基于Setter 的注入: 我们首先创建一个对象(不使用 arg-constructor),然后稍后使用 setter 更新依赖项或值s.(@NoArgsConstructor)
构造函数注入和 setter 注入之间有许多关键区别。
部分依赖: 可以使用 setter 注入,但不能通过构造函数注入。假设a中有3个属性 class,具有 3 个参数构造函数和 setters 方法。在这种情况下,如果 你只想传递一个 属性 的信息,可以通过 setter 仅方法。
覆盖: Setter注入覆盖构造函数注入。如果我们同时使用构造函数和 setter 注入,IOC 容器将 使用 setter 注入。
变化:我们可以通过setter注入轻松改变值。它不会像构造函数那样总是创建一个新的 bean 实例。所以 setter 注入比构造函数注入灵活。