Java 为什么Hibernate不需要参数构造函数?

Java 为什么Hibernate不需要参数构造函数?,java,hibernate,orm,factory-pattern,Java,Hibernate,Orm,Factory Pattern,无参数构造函数是一个 需求(Hibernate等工具的使用) 对该构造函数的反思 实例化对象) 我得到了这个摇摆不定的答案,但有人能进一步解释一下吗?谢谢Hibernate将实例化您的对象。所以它需要能够实例化它们。如果没有无参数构造函数,Hibernate将不知道如何实例化它,即传递什么参数 报告说: 4.1.1。实现一个无参数构造函数 所有持久类都必须有一个默认构造函数(可以是非公共的),以便Hibernate可以使用constructor.newInstance()实例化它们。建议在Hib

无参数构造函数是一个 需求(Hibernate等工具的使用) 对该构造函数的反思 实例化对象)


我得到了这个摇摆不定的答案,但有人能进一步解释一下吗?谢谢

Hibernate将实例化您的对象。所以它需要能够实例化它们。如果没有无参数构造函数,Hibernate将不知道如何实例化它,即传递什么参数

报告说:

4.1.1。实现一个无参数构造函数


所有持久类都必须有一个默认构造函数(可以是非公共的),以便Hibernate可以使用
constructor.newInstance()
实例化它们。建议在Hibernate中为运行时代理生成提供至少具有包可见性的默认构造函数

Hibernate需要创建实例作为查询的结果(通过反射),Hibernate依赖于实体的无参数构造函数,因此需要提供无参数构造函数。什么是不清楚的

Hibernate,以及通过反射创建对象的代码通常用于创建类的新实例。此方法需要公共无参数构造函数才能实例化对象。对于大多数用例,提供无参数构造函数不是问题


有一些基于序列化的黑客可以绕过没有参数构造函数的问题,因为序列化使用jvm魔术来创建对象而不调用构造函数。但这并不是在所有虚拟机上都可用。例如,可以创建没有公共no-arg构造函数的对象实例,但只能以所谓的“增强”模式运行,该模式仅在某些VM上可用。(详情请参见链接。)Hibernate的设计人员当然选择了保持与所有VM的兼容性,因此避免了此类把戏,并使用了官方支持的反射方法
Class.newInstance()
,需要无arg构造函数。

实际上,您可以实例化没有0-args构造函数的类;您可以获得一个类的构造函数列表,选择一个并使用伪参数调用它

虽然这是可能的,我想它会起作用,不会有问题,但你必须同意这是相当奇怪的

以Hibernate的方式构造对象(我相信它调用0-arg构造函数,然后可能通过反射直接修改实例的字段。也许它知道如何调用setter)有点违背了在Java中应该如何构造对象——使用适当的参数调用构造函数,以便新对象就是您想要的对象。我相信实例化一个对象然后对其进行变异有点“反Java”(或者我会说,反纯理论Java)——而且肯定的是,如果你通过直接的字段操作来实现这一点,它会变成封装和所有那些奇特的封装东西

我认为正确的方法是在Hibernate映射中定义如何使用正确的构造函数从数据库行中的信息实例化对象。。。但这将更加复杂-意味着两个Hibernate将更加复杂,映射将更加复杂。。。一切都要更加“纯洁”;我不认为这会比目前的方法有什么优势(除了感觉良好的“正确的方式”做事)


话虽如此,鉴于Hibernate方法不是很“干净”,拥有一个0-arg构造函数的义务并不是绝对必要的,但我可以理解这一要求,尽管我相信他们完全是基于“正确的方式”的理由,当他们偏离“正确的方式”时(尽管是出于合理的原因)远远早于此。

hibernate是一个支持字段或属性访问策略的ORM框架。但是,它不支持基于构造函数的映射-可能是您想要的因为一些问题,比如

如果类包含大量构造函数,会发生什么

public class Person {

    private String name;
    private Integer age;

    public Person(String name, Integer age) { ... }
    public Person(String name) { ... }
    public Person(Integer age) { ... }

}
正如您所看到的,您要处理一个不一致的问题,因为Hibernate无法假设应该调用哪个构造函数。例如,假设您需要检索一个存储的Person对象

Person person = (Person) session.get(Person.class, <IDENTIFIER>);
根据API文档

该类被实例化,就像被一个新表达式实例化一样,该表达式的参数列表为

故事的寓意

类似于

new Person();

除此之外

通过反射创建具有无参数构造函数的对象,然后通过反射用数据填充其属性,要比尝试将数据与参数化构造函数的任意参数相匹配容易得多,其中包括更改名称/命名冲突、构造函数内未定义的逻辑、,参数集与对象的属性不匹配,等等


许多ORM和序列化程序都需要无参数构造函数,因为通过反射的参数化构造函数非常脆弱,无参数构造函数为应用程序提供稳定性,并为开发人员提供对对象行为的控制。

Hibernate使用代理进行延迟加载。如果您不定义构造函数或使其私有化,一些事情可能仍然可以工作——不依赖于代理机制的事情。例如,直接使用查询API加载对象(没有构造函数)

但是,如果使用session.load method(),由于构造函数不可用,您将面临来自代理生成器库的实例化异常

这家伙报告了类似的情况:


查看Java语言规范的这一部分,它解释了静态和非静态内部类之间的区别:

静态内部类在概念上与.java文件中声明的常规常规类没有什么不同

由于Hibernate需要独立于项目实例实例化ProjectPK,ProjectPK需要是一个静态内部类,或者在它自己的.j中声明
Person.class.newInstance();
Person.class.newInstance();
new Person();