一、反射的用途
反射通常由需要检查或修改在 Java 虚拟机中运行的应用程序的运行时行为的能力的程序使用。这是一个相对高级的功能,只能由对语言基础知识有很强掌握的开发人员使用。考虑到这一点,反射是一种强大的技术,可以使应用程序执行原本不可能完成的操作。
二、反射的缺点
反射很强大,但不应该乱用。如果可以在不使用反射的情况下执行操作,那么最好避免使用它。通过反射访问代码时应牢记以下问题。
- 性能开销
由于反射涉及动态解析的类型,因此无法执行某些 Java 虚拟机优化。因此,反射操作的性能比非反射操作慢,因此应避免在性能敏感的应用程序中频繁调用的代码段中使用反射操作。 - 安全限制
反射需要运行时权限,在安全管理器下运行时可能不存在该权限。对于必须在受限安全上下文(例如 Applet)中运行的代码来说,这是一个重要的考虑因素。 - 内部结构暴露
由于反射允许代码执行在非反射代码中非法的操作(例如访问private字段和方法),因此使用反射可能会导致意外的副作用,这可能会导致代码功能失调并可能破坏可移植性。反射代码破坏了抽象,因此可能会随着平台的升级而改变行为。三、什么是非法的反射访问
默认情况下,对包具有运行时反射访问权限的模块可以看到包的public类型(及其嵌套public和protected类型)。但是,其他模块中的代码可以访问公开包中的所有类型以及这些类型中的所有成员,包括privatevia 成员 setAccessible。即,访问public类型(及其嵌套public和protected类型)被认为是合法的,访问privatevia 成员被认为是非法。四、什么定义了非法反射访问?
从JDK9开始默认情况下放宽了某些 JDK 包的强封装,种放松是在运行时由新的启动器选项--illegal-access
控制的, --illegal-access=permit 打开运行时映像中每个模块中的每个包,以在所有未命名模块中进行编码,即,如果该包存在于 JDK 8 中,则在类路径上进行编码。这可以实现静态访问(即通过编译的字节码)和深度访问通过平台的各种反射 API 进行反射访问。
对任何此类包的第一次反射访问操作都会导致发出警告,但此后不会发出警告。此单个警告描述了如何启用进一步的警告。该警告无法被抑制。此模式是 JDK 9 中的默认模式。它将在未来版本中逐步淘汰并最终删除。--illegal-access=warn 与permit 相同,只是为每个非法反射访问操作发出警告消息。
--illegal-access=debug 与warn相同,只是针对每个非法反射访问操作都会发出警告消息和堆栈跟踪。
--illegal-access=deny 禁用所有非法访问操作,但由其他命令行选项启用的操作除外,例如--add-opens.此模式将成为未来版本中的默认模式。
五、如何解决?
可以使用“--add-opens”
--add-opens <source-module>/<package>=<target-module>(,<target-module>)*
假设有一个错误它来自 模块 java.base,包 java.lang:
java.lang.ClassLoader.findLoadedClass(java.lang.String)
按照上面的样式带入:
java --add-opens=java.base/java.lang=ALL-UNNAMED -jar example.jar