在复制构造函数中使用直接字段访问而不是getter会导致空指针异常

时间:2019-01-15 07:03:24

标签: java hibernate copy-constructor lombok intellij-lombok-plugin

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

我有一堆实体。它们像树一样组织。渴望获取链接的实体。

我将Hibernate,Lombok和IntelliJ用于调试器。

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

 this.someField= original.someField

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

enter image description here

尽管如此,它仍可以使用吸气剂工作。

 this.setSomeField(original.getSomeField())

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

enter image description here

有人可以向我解释为什么无法直接进行现场访问吗?
(我问的是技术原因,而不是诸如“您应始终使用吸气剂”之类的哲学原因)。

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

谢谢。

2 个答案:

答案 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之后的运算符,我认为字段中的值应该出现。