什么是非法反射访问?

新手上路,请多包涵

Java 9 中有很多关于非法反射访问的问题。

我发现了很多关于解决错误消息的讨论,但我很想知道非法反射访问实际上是什么。

所以我的问题是:

什么定义了非法反射访问以及什么情况会触发警告?

我已经收集到它与 Java 9 中引入的封装原则有关,但我找不到关于它们如何结合在一起、什么触发警告以及在什么情况下的解释。

原文由 Tschallacka 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

除了了解模块及其各自包之间的访问之外。我相信它的症结在于 模块系统#Relaxed-strong-encapsulation ,我会挑选其中的相关部分来尝试回答这个问题。

什么定义了非法反射访问以及什么情况会触发警告?

为了帮助迁移到 Java-9,可以放松对模块的强封装。

  • 实现可以提供 _静态访问_,即通过编译的字节码。

  • 可以提供一种方法来调用其运行时系统,其中一个或多个模块的一个或多个包对 所有未命名模块 中的代码开放,即类路径上的代码。如果以这种方式调用运行时系统,并且如果这样做,反射 API 的某些调用会成功,否则它们会失败。

在这种情况下,您实际上最终进行了 “非法” 的 _反射访问_,因为在纯模块化世界中,您不应该进行此类访问。

这一切是如何联系在一起的,在什么情况下会触发警告?

这种封装的放松在运行时由一个新的启动器选项 --illegal-access 在 Java9 中默认等于 permitpermit 模式确保

对任何此类包的第一次反射访问操作会导致发出警告,但在此之后不会发出警告。此单个警告描述了如何启用更多警告。无法抑制此警告。

这些模式可配置为值 debug (每次此类访问的消息和堆栈跟踪)、 warn (每次此类访问的消息)和 deny 此类操作)。


在应用程序上调试和修复的几件事是:-

  • 使用 --illegal-access=deny 运行它,以了解并避免在没有包含此类指令( opens )的模块声明或显式使用 --add-opens 的情况下从一个模块 打开 包到另一个模块 --- 虚拟机参数。
  • 可以使用带有 --jdk-internals 选项的 jdeps 工具识别从编译代码到 JDK 内部 API 的静态引用

检测到非法反射访问操作时发出的警告消息具有以下形式:

 WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM

在哪里:

$PERPETRATOR 是包含调用相关反射操作的代码以及代码源(即 JAR 文件路径)(如果可用)的类型的完全限定名称,并且

$VICTIM 是描述正在访问的成员的字符串,包括封闭类型的完全限定名称

此类示例警告的问题: = JDK9:发生了非法反射访问操作。 org.python.core.PySystemState

最后也是重要的一点,在尝试确保您不会面临此类警告并且未来安全时,您需要做的就是确保您的模块不会进行那些非法的反射访问。 :)

原文由 Naman 发布,翻译遵循 CC BY-SA 4.0 许可协议

我发现了一篇关于 Java 9 模块系统的 Oracle 文章

默认情况下,模块中的类型不能被其他模块访问,除非它是公共类型并且您导出它的包。您只公开要公开的包。对于 Java 9,这也适用于反射。

正如 https://stackoverflow.com/a/50251958/134894 中所指出的,JDK8 和 JDK9 的 AccessibleObject#setAccessible 之间的差异具有指导意义。具体来说,JDK9增加了

如果满足以下任何条件,则类 C 中的调用者可以使用此方法来启用对声明类 D 的成员的访问:

  • C和D在同一个模块中。
  • 成员是公共的,D 在包含 D 的模块导出到至少包含 C 的模块的包中是公共的。
  • 该成员是受保护的静态成员,D 在包含 D 的模块导出到至少包含 C 的模块的包中是公共的,并且 C 是 D 的子类。
  • D 在包含 D 的模块至少对包含 C 的模块打开的包中。未命名和打开模块中的所有包都对所有模块打开,因此当 D 在未命名或打开模块中时,此方法总是成功。

这突出了模块及其导出的重要性(在 Java 9 中)

原文由 ptomli 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题