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

无参构造函数是一个需求(像Hibernate这样的工具在这个构造函数中使用reflection来实例化对象)。

我得到了这个手势波形的答案,但有人可以进一步解释吗? 谢谢

Hibernate和一般通过reflection创build对象的代码使用Class<T>.newInstance()来创build类的新实例。 这个方法需要一个公共的无参数构造函数来实例化对象。 对于大多数用例来说,提供一个无参数构造函数并不是问题。

有基于序列化的黑客可以解决没有一个无参数的构造函数,因为序列化使用jvm魔术来创build对象,而无需调用构造函数。 但是这在所有虚拟机中都不可用。 例如, XStream可以创build没有公共无参数构造函数的对象的实例,但只能通过仅在特定虚拟机上可用的所谓“增强”模式运行。 Hibernate的devise人员当然select保持与所有虚拟机的兼容性,避免使用这种技巧,并使用官方支持的reflection方法Class<T>.newInstance() ,该方法需要一个无参数的构造函数。

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

hibernate文档说:

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

所有的持久化类必须有一个默认的构造函数(可以是非公有的),这样Hibernate可以使用Constructor.newInstance()来实例化它们。 build议您在Hibernate中有一个默认的构造函数,至less包的可见性用于运行时代理生成。

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

Hibernate调用哪个构造函数来检索Person对象? 你知道吗 ?

最后,通过使用reflection,Hibernate可以通过其no-arg构造函数实例化一个类。 所以当你打电话

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

Hibernate将按如下方式实例化Person对象

 Person.class.newInstance(); 

根据API文档

这个类被实例化,就像通过一个带有参数列表的expression式一样

故事的道德启示

 Person.class.newInstance(); 

类似于

 new Person(); 

没有其他的

呃,对不起,每个人,但Hibernate不要求你的类必须有一个无参数的构造函数。 JPA 2.0规范要求它,这代表JPA非常蹩脚。 像JAXB这样的其他框架也需要它,代表这些框架也是非常蹩脚的。

(实际上,JAXB据说允许实体工厂,但是它坚持要自己实例化这些工厂,要求他们拥有一个无参数的构造函数 ,在我的书中,这个构造函数和不允许工厂一样好, !)

但是Hibernate不需要这样的事情。

Hibernate支持拦截机制(请参阅文档中的“拦截器” ),它允许您使用任何所需的构造函数参数来实例化对象。

基本上,你所做的是,当你设置hibernate的时候,你传递一个实现org.hibernate.Interceptor接口的对象,然后当它需要一个新的你的对象的实例的时候,hibernate会调用这个接口的instantiate()方法,所以你的方法的实现可以以任何你喜欢的方式new的对象。

我在一个项目中完成了它,它的function就像一个魅力。 在这个项目中,我尽可能通过JPA来做事情,而且当我没有别的select的时候,我只使用像拦截器这样的Hibernate特性。

Hibernate似乎有点不安全,因为在启动期间,它会为我的每个实体类发出一条信息消息,告诉我INFO: HHH000182: No default (no-argument) constructor for classclass must be instantiated by Interceptor INFO: HHH000182: No default (no-argument) constructor for class class must be instantiated by Interceptor ,但是后来我通过拦截器来实例化它们,并且对此感到高兴。

为了回答Hibernate以外的其他工具的“为什么”部分,答案是“绝对没有理由的”,这一点已经被hibernate拦截器的存在所证实。 有很多工具可以支持客户端对象实例化的一些类似的机制,但是它们不是,所以它们自己创build对象,所以它们必须要求无参数的构造函数。 我很想相信这是因为这些工具的创造者认为自己是忍者系统的程序员,他们创造出了一个充满魔法的框架,供无知的应用程序员使用,他们(他们认为)永远不会在他们最疯狂的梦中拥有一个需要像工厂模式这样的高级构造。 (好吧,我很想这么想,我其实不这么认为,我在开玩笑)

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

虽然这是可能的,我想这会工作,不会有问题,你必须同意这很奇怪。

按照Hibernate的方式构build对象(我相信它调用0-arg构造函数,然后它可能直接通过Reflection修改实例的字段,也许它知道如何调用setter)对于如何构造对象Java-使用适当的参数调用构造函数,以便新对象成为所需的对象。 我相信实例化一个对象然后对它进行变异有点“反Java”(或者我会说,反纯理论上的Java) – 当然,如果你通过直接的字段操作来做到这一点,那么它就是封装和所有那些花哨的封装的东西。

我认为这样做的正确方法是在Hibernate映射中定义如何使用适当的构造函数从数据库行中的信息实例化一个对象…但是这会更复杂 – 这意味着Hibernate将会是平坦的更复杂的是,绘图会更加复杂……而且都更加“纯粹”; 我认为这不会比现在的做法更有优势(除了“以正确的方式做事”感觉良好之外)。

话虽如此,并且看到Hibernate的方法不是很“干净”,但有一个0-参数构造函数的义务并不是非常必要的,但我可以理解这个需求,尽pipe我相信他们是以纯粹的“正确方式“的理由,当他们偏离了”正确的方式“(虽然有合理的理由)之前。

Hibernate需要通过查询来创build实例(通过reflection),Hibernate依赖于实体的无参数构造函数,因此您需要提供一个无参数的构造函数。 什么不清楚?

通过reflection创build具有无参数构造函数的对象,然后通过reflection来填充其属性和数据,要比试图将数据匹配到参数化构造函数的任意参数,更改名称/命名冲突,构造函数中的未定义逻辑,参数集与对象的属性不匹配等等。

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

Hibernate使用代理进行延迟加载。 如果你没有定义一个构造函数或者使其成为私有的,那么一些东西可能仍然有效 – 那些不依赖于代理机制的东西。 例如,直接使用查询API加载对象(不带构造函数)。

但是,如果使用session.load方法(),由于构造函数不可用,您将面临来自代理生成器库的InstantiationException。

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

http://kristian-domagala.blogspot.com/2008/10/proxy-instantiation-problem-from.html

查看Java语言规范的这一部分,它解释了静态和非静态内部类之间的区别: http : //java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.3

静态内部类在概念上与在.java文件中声明的普通常规类没有区别。

由于Hibernate需要独立于Project实例来实例化ProjectPK,所以ProjectPK需要是一个静态的内部类,或者在它自己的.java文件中声明。

参考org.hibernate.InstantiationException:没有默认的构造函数