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