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

NIr*_*odi 7 java java-platform-module-system java-9

我正在使用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
Run Code Online (Sandbox Code Playgroud)

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

public static void main(String args[]){
   System.out.println(Reflection.getCallerClass(3));
}
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 7

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

获取直接调用者类
Class<?> c = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
                        .getCallerClass();
Run Code Online (Sandbox Code Playgroud) 获取堆栈中的第n个调用者(例如,第三个,如您的示例中所示):
Class<?> c = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk(s ->
     s.map(StackWalker.StackFrame::getDeclaringClass).skip(3).findFirst().orElse(null));
Run Code Online (Sandbox Code Playgroud)

  • 这在 JDK10 之后有效,支持可见性作为正确答案。 (2认同)

Tag*_*eev 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
Run Code Online (Sandbox Code Playgroud)

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

  • 实际上,`sun.reflect.Reflection`已移至`jdk.unsupported`模块.所以它至少会出现在Java 10之前. (2认同)

Nic*_*lai 5

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

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

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

--add-exports java.base/sun.reflect=ALL-UNNAMED
Run Code Online (Sandbox Code Playgroud)

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


NIr*_*odi 3

java -cp classes -XaddExports:java.base/sun.reflect Test
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

java -cp classes -XaddExports:java.base/sun.reflect Test
Run Code Online (Sandbox Code Playgroud)

  • 答案有些误导:(1)紧凑的轮廓与之无关;(2) 对于所有其他类型的包也同样失败;(3) 错误消息和建议的解决方案已过时。请参阅[我的答案](http://stackoverflow.com/a/41824999/2525313)。 (3认同)