无参数构造函数是必需的(像Hibernate这样的工具在此构造函数上使用反射来实例化对象)。
我得到了这个手挥手的答案,但是有人可以进一步解释吗?谢谢
Caused by: org.hibernate.InstantiationException: No default constructor for entity: : hibernate.tutorial.Student
像我刚才遇到的情况一样进行报告
无参数构造函数是必需的(像Hibernate这样的工具在此构造函数上使用反射来实例化对象)。
我得到了这个手挥手的答案,但是有人可以进一步解释吗?谢谢
Caused by: org.hibernate.InstantiationException: No default constructor for entity: : hibernate.tutorial.Student
像我刚才遇到的情况一样进行报告
Answers:
休眠,通常通过反射创建对象的代码Class<T>.newInstance()
用于创建类的新实例。此方法需要一个公共的无参数构造函数才能实例化该对象。对于大多数使用情况,提供无参数构造函数不是问题。
有一些基于序列化的技巧可以解决没有no-arg构造函数的问题,因为序列化使用jvm magic创建对象而无需调用构造函数。但这并非在所有VM上都可用。例如,XStream可以创建没有公共no-arg构造函数的对象实例,但只能通过在所谓的“增强”模式下运行,该模式仅在某些VM上可用。(有关详细信息,请参见链接。)Hibernate的设计人员肯定会选择保持与所有VM的兼容性,因此避免了此类技巧,并使用了正式支持的反射方法Class<T>.newInstance()
,该方法需要无参数的构造函数。
setAccessible(true)
在其上。
ObjectInputStream
,在sun.reflect.ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToGetInstanceOf, Object.class.getConstructor()).newInstance()
没有默认构造函数的情况下实例化对象的操作(对于Windows为
It can have package visibility and Hibernate should setAccessible(true)
。是否it
意味着该类通过反射实例化?那是什么Hibernate should setAccessible(true)
意思呢?
休眠实例化您的对象。因此,它需要能够实例化它们。如果没有no-arg构造函数,则Hibernate将不知道如何实例化它,即传递什么参数。
在Hibernate文档说:
4.1.1。实现无参数构造函数
所有持久类都必须具有默认构造函数(可以是非公共的),以便Hibernate可以使用实例化它们Constructor.newInstance()
。建议您使用默认构造函数,至少具有包可见性,以便在Hibernate中生成运行时代理。
呃,对不起大家,但是Hibernate并没有要求你的类必须有一个参数的构造函数。JPA 2.0规范对此有要求,对于JPA而言,这非常la脚。其他框架(例如JAXB)也需要它,对于那些框架而言,这也非常la脚。
(实际上,JAXB应该允许实体工厂,但是它坚持要自己实例化这些工厂,要求它们有一个--guess what--无参数构造函数,在我的书中这和不允许工厂一样好;这真是la脚。 !)
但是Hibernate不需要这样的东西。
Hibernate支持一种拦截机制(请参阅文档中的“ Interceptor”),该机制允许您使用所需的构造函数参数来实例化您的对象。
基本上,您要做的是在设置休眠状态时将其传递给实现org.hibernate.Interceptor
接口的对象,然后休眠状态将instantiate()
在需要它的新实例时调用该接口的方法,因此您可以实现该方法new
以您喜欢的任何方式来处理您的对象。
我已经在一个项目中完成了它,它就像一个魅力。在这个项目中,我会尽可能通过JPA进行操作,并且在没有其他选择时,我只会使用Hibernate功能(例如拦截器)。
Hibernate似乎对此不太安全,因为在启动期间它会为我的每个实体类发出一条信息消息,告诉我INFO: HHH000182: No default (no-argument) constructor for class
和class must be instantiated by Interceptor
,但是后来我确实通过拦截器实例化了它们,对此感到满意。
对于Hibernate以外的工具,要回答问题的“为什么”部分,答案是“绝对没有充分的理由”,这已通过休眠拦截器的存在得到了证明。那里有许多工具本来可以支持某种类似的机制来实现客户端对象实例化,但是它们却没有,因此它们是自己创建对象的,因此它们必须要求无参数的构造函数。我很容易相信这种情况的发生,因为这些工具的创建者将自己视为忍者系统程序员,他们创建了充满魔力的框架,供无知的应用程序程序员使用,他们(所以他们认为)绝不会在他们最疯狂的梦想中拥有需要诸如工厂模式这样的高级构造。(好的,这样想。我实际上并不这么认为。开玩笑。)
Caused by: org.hibernate.InstantiationException: No default constructor for entity: : hibernate.tutorial.Student
事件javax.persistence.*;
是最近发生的,因为已被使用,并且仅org.hibernate
当创建Session, SessionFactory, and Configuration
休眠是支持字段或属性访问策略的ORM框架。但是,它不支持基于构造函数的映射-也许您想要什么?-由于某些问题,例如
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>);
Hibernate应该调用哪个构造函数来检索Person对象?你知道吗 ?
2º最后,通过使用反射,Hibernate可以通过其无参数构造函数实例化一个类。所以当你打电话
Person person = (Person) session.get(Person.class, <IDENTIFIER>);
Hibernate将实例化您的Person对象,如下所示
Person.class.newInstance();
根据API文档
就像通过带有空参数列表的新表达式实例化该类一样
故事的道德启示
Person.class.newInstance();
类似于
new Person();
没有其他的
name
和age
?如果不是,那么稍后使用另一个构造函数?
实际上,您可以实例化没有0-args构造函数的类。您可以获得一个类的构造函数的列表,选择一个并使用伪造的参数调用它。
尽管这是可能的,而且我想它会起作用并且不会出现问题,但您必须同意这很奇怪。
以Hibernate的方式构造对象(我相信它会调用0-arg构造函数,然后它可能直接通过Reflection修改实例的字段。也许它知道如何调用setter)与应该如何构造对象有关。 Java-使用适当的参数调用构造函数,以便新对象是您想要的对象。我相信实例化一个对象然后对其进行变异有点“反Java”(或者我会说反纯理论Java),并且肯定的是,如果您通过直接的字段操作来做到这一点,它将进行封装以及所有奇特的封装工作。
我认为执行此操作的正确方法是在Hibernate映射中定义如何使用适当的构造函数从数据库行中的信息实例化对象...但这将更加复杂-意味着两个Hibernate都将甚至更复杂的是,映射也将更加复杂……而且都将变得更加“纯粹”。而且我认为这不会比目前的方法有优势(除了对“正确的方式”做事感到满意之外)。
话虽如此,并且看到Hibernate的方法不是很“干净”,但严格来说没有必要拥有0-arg构造函数,但我可以从某种程度上理解这一要求,尽管我相信他们纯粹是通过“正确的方式”完成的”,因为他们早于“正确的方式”(尽管出于合理的原因)偏离了。
Hibernate需要根据查询(通过反射)创建实例,Hibernate为此依赖于实体的no-arg构造函数,因此您需要提供no-arg构造函数。有什么不清楚的?
与尝试将数据与参数化构造函数的任意参数进行匹配,更改名称/命名冲突,构造函数内部未定义的逻辑相比,通过反射使用无参数的构造函数创建对象,然后通过反射填充数据的属性要容易得多,参数集与对象的属性不匹配等。
许多ORM和序列化程序都需要无参数构造函数,因为通过反射进行参数化的构造函数非常脆弱,并且无参数构造函数既为应用程序提供了稳定性,又为开发人员提供了对对象行为的控制。
Hibernate使用代理进行延迟加载。如果您没有定义构造函数或将其设为私有,则可能仍会发生一些事情-不依赖于代理机制的那些事情。例如,直接使用查询API加载对象(不带构造函数)。
但是,如果您使用session.load method(),则由于构造函数不可用,代理生成器库将面临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文件中声明。
The no-argument constructor is a requirement
错误的断言,以及所有继续解释其原因的答案,而不必怀疑事实是否如此(包括被接受的答案,甚至得到了赏金)都是错误的。看到这个答案:stackoverflow.com/a/29433238/773113