它必须是Java 101,但我不知道为什么我不能使用直接字段访问,以及为什么我不得不在复制构造函数中使用getter。
我有一堆实体。它们像树一样组织。渴望获取链接的实体。
我将Hibernate,Lombok和IntelliJ用于调试器。
当我从根部拉出一个实体树时,会得到一棵对象树。我们称其为“原始”。由于与业务需求有关的某种原因,我需要复制它(我们称其为“副本”)。我使用复制构造函数来实现。 我首先使用直接字段访问编写了副本构造函数的版本。
this.someField= original.someField
它没有用。当我检查调试器时,我看到original.someField(以及其他字段)始终为null。
尽管如此,它仍可以使用吸气剂工作。
this.setSomeField(original.getSomeField())
在调试器中,我可以看到字段在original.handler.target中是“设置”的。 (我不知道什么是handler.target是)。
有人可以向我解释为什么无法直接进行现场访问吗?
(我问的是技术原因,而不是诸如“您应始终使用吸气剂”之类的哲学原因)。
我也很高兴知道什么是“ handler.target”。
谢谢。
答案 0 :(得分:3)
您遇到的完全不是Java 101问题。 Hibernate具有一项称为“延迟加载”的功能,该功能允许框架将(可能很重的)对象的加载推迟到以后的某个时间点,仅在需要时。例如,当您加载一个account
对象只是为了检查active
标志时,这非常方便,但是绝对不需要使用此帐户获取所有登录历史记录。
现在是“仅在需要时”部分:吸气剂。
Hibernate知道在对象图的父对象上调用getter时确实需要该可延迟加载的对象。在执行此操作之前,延迟引用的对象将保持为空。直接变量访问绕过执行此“技巧”的代理逻辑,这就是您获得意外的空值的方式。通过字段的getter访问该字段时,代理代码将启动,加载会发生,并且您可以将对象找回。
handler/target/etc
只是由于代理而需要使用的其他引用。 (您的account
将不再有直接的accounthistory
变量,而是一个accounthistory_proxy
,而后者又会有一个accounthistory_real
)
答案 1 :(得分:0)
据我了解,您正在获取代理对象,一旦调用getter方法,您将获得实际的对象。请问一旦您再次调用gettter方法,之后对象的字段仍然为null即可检查吗?尝试使用。调用getter之后的运算符,我认为字段中的值应该出现。