2

它必须是 Java 101,但我不知道为什么我不能使用直接字段访问以及为什么我不得不在复制构造函数中使用 getter。

我有一堆实体。它们像树一样组织起来。链接的实体被急切地获取。

我使用 Hibernate、Lombok 和 IntelliJ 作为调试器。

当我从根部拉出其中一个实体树时,我得到一棵对象树。我们称它为“原始”。由于某些与业务需求相关的原因,我需要复制它(我们称之为“副本”)。我使用复制构造函数来做到这一点。我首先使用直接字段访问编写了复制构造函数的一个版本。

 this.someField= original.someField

它没有用。当我检查调试器时,我看到 original.someField(以及其他字段)始终为空。

在此处输入图像描述

不过,它可以使用吸气剂。

 this.setSomeField(original.getSomeField())

在调试器中,我可以看到 original.handler.target 中的字段已“设置”。(我不知道 handler.target 是什么)。

在此处输入图像描述

有人可以向我解释为什么直接字段访问不起作用吗?
(我问的是技术原因,而不是哲学上的原因,比如“你应该总是使用吸气剂”等)。

我也很高兴知道什么是“handler.target”。

提前致谢。

4

2 回答 2

3

你遇到的根本不是 Java 101 的问题。Hibernate 有一个称为延迟加载的功能,它允许框架将(可能很重的)对象的加载推迟到稍后的时间点,仅在需要时才加载。例如,当您加载一个account对象只是为了检查一个active标志时,这很方便,但绝对不需要使用此帐户获取的所有登录历史记录。

现在是“仅在需要时”部分:吸气剂。

当您在对象图中调用父对象的 getter 时,Hibernate 知道您确实需要那个可延迟加载的对象。在您这样做之前,延迟引用的对象保持为空。直接变量访问绕过执行此“技巧”的代理逻辑,这就是您获得意外空值的方式。当通过它的 getter 访问该字段时,代理代码启动,加载发生,然后您将对象取回。

由于代理,这handler/target/etc只是您需要的额外参考。(您account将不再有直接accounthistory变量,而是一个accounthistory_proxy,而后者又将有一个accounthistory_real

于 2019-01-15T07:32:02.053 回答
0

根据我的理解,您正在获取代理对象,一旦您调用 getter 方法,您将获得实际对象。请您在调用 gettter 方法之后检查对象的字段是否仍然为 null ?尝试使用 . 调用 getter 后的运算符,我认为字段中的值应该出现。

于 2019-01-15T07:13:15.447 回答