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

pcww981p  于 2021-07-13  发布在  Java
关注(0)|答案(9)|浏览(322)

无参数构造函数是一个需求(hibernate等工具使用对该构造函数的反射来示例化对象)。
我得到了一个摇摆不定的答案,但有人能进一步解释一下吗?谢谢

qfe3c7zg

qfe3c7zg1#

hibernate和通过反射创建对象的代码 Class<T>.newInstance() 创建类的新示例。此方法需要一个public no arg构造函数来示例化对象。对于大多数用例,提供无参数构造函数不是问题。
有一些基于序列化的黑客可以绕过没有无参数构造函数的问题,因为序列化使用jvm魔术来创建对象而不调用构造函数。但这并不是在所有虚拟机上都可用。例如,xstream可以创建没有公共no-arg构造函数的对象的示例,但只能以所谓的“增强”模式运行,这种模式仅在某些vm上可用(hibernate的设计人员当然选择保持与所有vm的兼容性,因此避免了这些技巧,并使用官方支持的反射方法 Class<T>.newInstance() 需要无参数构造函数。

fzsnzjdm

fzsnzjdm2#

hibernate示例化对象。所以它需要能够示例化它们。如果没有no-arg构造函数,hibernate将不知道如何示例化它,即传递什么参数。
hibernate文档说明:
4.1.1. 实现无参数构造函数
所有持久类都必须有一个默认构造函数(可以是非公共的),以便hibernate可以使用 Constructor.newInstance() . 建议您在hibernate中使用至少具有包可见性的默认构造函数来生成运行时代理。

m2xkgtsf

m2xkgtsf3#

呃,对不起大家,但是hibernate不要求类必须有无参数构造函数。JPA2.0规范需要它,而这对于jpa来说是非常蹩脚的。像jaxb这样的其他框架也需要它,这对于那些框架来说也是非常蹩脚的。
(实际上,jaxb应该允许实体工厂,但它坚持自己示例化这些工厂,要求它们有一个——猜怎么着——无参数构造函数,在我的书中,这和不允许工厂一样好;这是多么蹩脚啊!)
但是冬眠并不需要这样的东西。
hibernate支持截取机制(请参阅文档中的“interceptor”),它允许您用所需的构造函数参数示例化对象。
基本上,当您设置hibernate时,您会向它传递一个实现 org.hibernate.Interceptor 接口,然后hibernate将调用 instantiate() 方法,以便您的方法实现可以 new 你喜欢什么样的东西。
我在一个项目中做过,效果很好。在这个项目中,我尽可能地通过jpa进行操作,并且我只在没有其他选择的情况下使用hibernate特性,比如拦截器。
hibernate似乎对此有点不安全,因为在启动期间,它会为我的每个实体类发出一条信息消息,告诉我 INFO: HHH000182: No default (no-argument) constructor for class 以及 class must be instantiated by Interceptor ,但后来我用拦截器示例化了它们,它对此很满意。
对于hibernate以外的工具,要回答问题的“为什么”部分,答案是“完全没有理由”,hibernate拦截器的存在证明了这一点。有很多工具本来可以支持一些类似的客户机对象示例化机制,但是它们不支持,所以它们自己创建对象,所以它们必须需要无参数构造函数。我很想相信这是因为这些工具的创造者认为他们自己是忍者系统程序员,他们创造了充满魔力的框架供无知的应用程序程序员使用,他们(他们这么认为)在他们最疯狂的梦想中永远不会需要像。。。工厂模式(好吧,我想是的。我其实不这么认为。我在开玩笑。)

3htmauhk

3htmauhk4#

hibernate是一个支持字段或属性访问策略的orm框架。但是,它不支持基于构造函数的Map-也许您想要什么因为一些问题,比如
1º 如果您的类包含大量构造函数,会发生什么

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>);

哪个构造函数应该休眠调用来检索person对象?你能看见吗?
2º 最后,通过使用反射,hibernate可以通过其no-arg构造函数示例化一个类。所以当你打电话的时候

Person person = (Person) session.get(Person.class, <IDENTIFIER>);

hibernate将示例化person对象,如下所示

Person.class.newInstance();

根据api文件
该类被示例化为一个带有空参数列表的新表达式
故事的寓意

Person.class.newInstance();

类似于

new Person();

没别的了

4bbkushb

4bbkushb5#

hibernate需要创建示例作为查询的结果(通过反射),hibernate依赖于实体的no-arg构造函数,因此需要提供no-arg构造函数。什么不清楚?

sulc1iza

sulc1iza6#

实际上,您可以示例化没有0-args构造函数的类;你可以得到一个类的构造器列表,选择一个并用伪参数调用它。
虽然这是可能的,我想它会工作,不会有问题,你会同意这是相当奇怪的。
以hibernate的方式构造对象(我相信它调用0-arg构造函数,然后可能通过反射直接修改示例的字段)。也许它知道如何调用setters,这与java中应该如何构造一个对象有点矛盾——用适当的参数调用构造函数,这样新对象就是您想要的对象。我相信示例化一个对象,然后对其进行变异是有点“反java”(或者我会说,反纯理论java)的——而且肯定的是,如果你通过直接的字段操作来实现这一点,它就变成了封装和所有那些奇特的封装东西。
我认为正确的方法是在hibernateMap中定义如何使用正确的构造函数从数据库行中的信息示例化一个对象。。。但这将更加复杂-意味着两个休眠将更加复杂,Map将更加复杂。。。一切都要更“纯洁”;我不认为这比目前的方法有什么优势(除了感觉做事情“正确的方式”很好)。
话虽如此,鉴于hibernate方法不是很“干净”,拥有一个0-arg构造函数的义务并不是严格必要的,但是我可以理解这一要求,尽管我相信他们完全是基于“正确的方式”的理由这样做的,而在那之前他们就偏离了“正确的方式”(尽管有合理的理由)。

wr98u20j

wr98u20j7#

通过反射用无参数构造函数创建对象,然后通过反射用数据填充其属性,要比尝试将数据与参数化构造函数的任意参数进行匹配容易得多,因为名称/命名冲突不断变化,构造函数中的逻辑未定义,参数集与对象的属性不匹配,等等。
许多orms和序列化程序需要无参数构造函数,因为通过反射实现的参数化构造函数非常脆弱,无参数构造函数既为应用程序提供了稳定性,也为开发人员提供了对对象行为的控制。

mbyulnm0

mbyulnm08#

hibernate使用代理进行延迟加载。如果不定义构造函数或使其私有化,那么一些事情可能仍然可以工作—那些不依赖于代理机制的事情。例如,直接使用queryapi加载对象(没有构造函数)。
但是,如果使用session.load method(),由于构造函数不可用,您将面临来自代理生成器库的示例化异常。
这家伙报告了类似的情况:
http://kristian-domagala.blogspot.com/2008/10/proxy-instantiation-problem-from.html

iklwldmw

iklwldmw9#

查看java语言规范的这一部分,它解释了静态和非静态内部类之间的区别:http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.3
静态内部类在概念上与在.java文件中声明的常规常规类没有区别。
由于hibernate需要独立于项目示例示例化projectpk,projectpk要么是一个静态的内部类,要么在它自己的.java文件中声明。
引用org.hibernate.instantiationexception:无默认构造函数

相关问题