如何在jdk9 / java-9中使用sun.reflect包?

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

 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)); } 

适用于较新的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。

这个答案已经过时了 – 请检查一下这个 !

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

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

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

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

这些sun.*软件包从来都不是官方API的一部分,并且不能保证存在,即使在Java 9之前的JVM中也是如此。为将来完全消失做好准备,甚至不能通过某些选项恢复。 值得庆幸的是,有一个官方API涵盖了这个function,消除了对非官方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)); 
 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 

使用迁移文档中提到的最新版本和更改来更新线程。 尽管如此,@ Holger正确地指出了这一点。

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

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

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

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