如何将类文字编译为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′
-
// //由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开始,类文字被视为实常数,使用单个ldc
或ldc_w
指令加载到操作数堆栈,就像使用String
文字一样。 不同之处在于常量池项的类型,它指的是String
常量的Class_info
和Class
常量的Class_info
。
作为旁注,从Java 7开始,Java字节码甚至允许加载MethodType
或MethodHandle
类型的常量,它们没有实际的Java语言等价物。
见ldc
:
索引是一个无符号字节,必须是当前类(第2.6节)的运行时常量池的有效索引。 索引处的运行时常量池条目必须是
int
或float
类型的运行时常量,或者是对字符串文字的引用,或者是对类,方法类型或方法句柄的符号引用(第5.1节)。如果运行时常量池条目是
int
或float
类型的运行时常量,则该运行时常量的数值将分别作为int
或float
推送到操作数堆栈。否则,如果运行时常量池条目是
reference
表示字符串文字(第5.1节)的类String
实例的reference
,则对该实例的reference
值将被推送到操作数堆栈。否则,如果运行时常量池条目是对类的符号引用(第5.1节),则解析命名类(第5.4.3.1节),并且
reference
表示该类值的Class
对象的reference
将被推送到操作数堆栈。否则,运行时常量池条目必须是对方法类型或方法句柄的符号引用(第5.1节)。 解析了方法类型或方法句柄(第5.4.3.5节),并将对
java.lang.invoke.MethodType
或java.lang.invoke.MethodHandle
,value的结果实例的reference
推送到操作数堆栈。
由于您提到了反编译器,大多数反编译器甚至能够识别更复杂的Java 5之前的代码模式并将它们反编译为类文字。 当然,简单的ldc
指令对于反编译来说是微不足道的。