如何将类文字编译为Java字节码?

public class A { } public class B { public static void b() { System.out.println(A.class); } } 

如何在B.class的字节码中编译类文字A.class ? 它是一个现场参考? 我在Oracle / Sun的字节码文档中找不到这一点。

无论是什么,反编译器都可以轻松地重建它:

 java -jar decompiler.jar B.class 

拿起JAVA_TOOL_OPTIONS:’ – Dfile.encoding = UTF8′

  1. // //由Procyon v0.5.30反​​编译// //

     public class B { public static void b() { System.out.println(A.class); <<< } } 

在Java 5之前,像A.class这样的类文字只是用于调用Class.forName("A")语法糖,将ClassNotFoundException转换为NoClassDefFoundError并根据编译器将结果缓存在合成static字段中包含类,即B

原因是类文字在Java 1.1中作为语言特性引入,但字节代码没有更改为对它有特殊支持。

从Java 5开始,类文字被视为实常数,使用单个ldcldc_w指令加载到操作数堆栈,就像使用String文字一样。 不同之处在于常量池项的类型,它指的是String常量的Class_infoClass常量的Class_info

作为旁注,从Java 7开始,Java字节码甚至允许加载MethodTypeMethodHandle类型的常量,它们没有实际的Java语言等价物。

ldc

索引是一个无符号字节,必须是当前类(第2.6节)的运行时常量池的有效索引。 索引处的运行时常量池条目必须是intfloat类型的运行时常量,或者是对字符串文字的引用,或者是对类,方法类型或方法句柄的符号引用(第5.1节)。

如果运行时常量池条目是intfloat类型的运行时常量,则该运行时常量的数值将分别作为intfloat推送到操作数堆栈。

否则,如果运行时常量池条目是reference表示字符串文字(第5.1节)的类String实例的reference ,则对该实例的reference 将被推送到操作数堆栈。

否则,如果运行时常量池条目是对类的符号引用(第5.1节),则解析命名类(第5.4.3.1节),并且reference表示该类Class对象的reference将被推送到操作数堆栈。

否则,运行时常量池条目必须是对方法类型或方法句柄的符号引用(第5.1节)。 解析了方法类型或方法句柄(第5.4.3.5节),并将对java.lang.invoke.MethodTypejava.lang.invoke.MethodHandle ,value的结果实例的reference推送到操作数堆栈。

由于您提到了反编译器,大多数反编译器甚至能够识别更复杂的Java 5之前的代码模式并将它们反编译为类文字。 当然,简单的ldc指令对于反编译来说是微不足道的。