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

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

我正在使用Hibernate,Lombok和IntelliJ作为调试器。

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

 this.someField= original.someField


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

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

但是,它可以使用吸气剂工作。

 this.setSomeField(original.getSomeField())


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

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

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

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

提前致谢。

最佳答案

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

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

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

handler/target/etc只是由于代理而需要使用的其他引用。 (您的account不再具有直接的accounthistory变量,而是一个accounthistory_proxy,而该变量又具有一个accounthistory_real

07-24 09:37
查看更多