7

我正在使用 jdk-9,我想sun.reflect.*在我的代码中使用包,但我得到了以下异常

Exception in thread 'main' java.lang.IllegalAccessError : class Test (in moudle: Unnamed Module) cannot access class sun.reflect.Reflaction (in module:java.base), sun.reflect is not exported to Unnamed module

当我使用 JDK-9 运行下面的示例代码时

public static void main(String args[]){
   System.out.println(Reflection.getCallerClass(3));
}
4

5 回答 5

10

这些sun.*包从来都不是官方 API 的一部分,也不保证存在,即使在 Java 9 之前的 JVM 中也是如此。为它们在未来完全消失做好准备,甚至无法通过某些选项恢复。值得庆幸的是,有一个涵盖此功能的官方 API,从而消除了对非官方 API 的需求。

获取直接调用者类
Class<?> c = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
                        .getCallerClass();
获取堆栈上的第 n 个调用者(例如第三个,如您的示例中):
Class<?> c = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk(s ->
     s.map(StackWalker.StackFrame::getDeclaringClass).skip(3).findFirst().orElse(null));
于 2017-01-26T17:27:55.363 回答
7

适用于较新的 OpenJDK 9 EA 版本。例如:

$ java -version
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+138)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+138, mixed mode)

$ javac Test.java
Test.java:5: warning: Reflection is internal proprietary API and may be removed in a future release
    System.out.println(Reflection.getCallerClass(3));
                       ^
Note: Test.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
1 warning

$ java Test
null

似乎它作为JDK-8137058的一部分在 9-ea+115 构建中得到了修复。因此,您可能正在使用较旧的 EA 版本。总的来说,@Holger 是对的:这个 API 很有可能在未来的 Java 版本中完全消失,所以考虑迁移到 StackWalker API。

于 2017-02-12T11:51:04.793 回答
5

此答案已过时 - 请检查此答案

模块系统的一个特点是,由于新的可访问性规则,它允许库开发人员强烈封装实现细节。简而言之,大多数类型sun.*com.sun.*包将不再可访问。这与 Sun 和后来的 Oracle 声明这些软件包不供公众使用是一致的。

一种解决方法是在编译和启动时使用命令行标志导出这些包:

--add-exports java.base/sun.reflect=ALL-UNNAMED

这会将包sun.reflect从模块java.base 导出到所有模块,包括未命名模块,该模块收集类路径上的所有类。

于 2017-01-24T09:52:22.920 回答
3
java -cp classes -XaddExports:java.base/sun.reflect Test

Jigsaw (java-9) 具有模块化概念,他们为 compact-1 设计了 ​​java.base 包,并封装了sun.reflect.*. 所以sun.reflect.*不能在外面访问。由于这个原因,它给出了例外

Exception in thread 'main' java.lang.IllegalAccessError : class Test (in moudle: Unnamed Module) cannot access class sun.reflect.Reflaction (in module:java.base), sun.reflect is not exported to Unnamed module

仍然提供向后兼容性,他们提供了使用该软件包的方法,如下所示。

java -cp classes -XaddExports:java.base/sun.reflect Test
于 2017-01-24T04:41:27.503 回答
0

使用迁移文档中提到的最新版本和引入的更改更新线程。不过,@Holger 已经正确地指出了这一点。

sun.reflect在 JDK 9 中仍可访问的包中的 API是:

  • sun.reflect.Reflection::getCallerClass(int)相反,请使用 stack-walking API,请参阅JEP 259:Stack-Walking API。
  • sun.reflect.ReflectionFactory.newConstructorForSerialization

默认情况下,这些 API 在运行时可访问。它们已移至jdk.unsupportedJRE 和 JDK 映像中存在的模块。需要这些 API 的模块必须声明对模块的依赖jdk.unsupported

sun.misc 和 sun.reflect 包中剩余的内部 API 已被移动,因为它们不应该被访问。如果您需要使用这些内部 API 之一,您可以使用--add-exports命令行选项打破封装。(类似于@NIrav 的回答)。尽管如文档中所建议的那样,此选项仅应用作迁移的临时帮助。

于 2017-09-05T06:06:31.970 回答