public class A {
}
public class B {
public static void b() {
System.out.println(A.class);
}
}
Run Code Online (Sandbox Code Playgroud)
如何A.class在B.class的字节码中编译类文字?它是一个现场参考?我在Oracle/Sun的字节码文档中找不到这一点.
无论是什么原因,反编译器都可以轻松地重建它:
java -jar decompiler.jar B.class
Run Code Online (Sandbox Code Playgroud)
拿起JAVA_TOOL_OPTIONS:' - Dfile.encoding = UTF8'
// //由Procyon v0.5.30反编译// //
public class B
{
public static void b() {
System.out.println(A.class); <<<
}
}
Run Code Online (Sandbox Code Playgroud)在Java 5之前,类文字A.class只是用于Class.forName("A")在引擎下调用的语法糖,将a转换ClassNotFoundException为a,NoClassDefFoundError并且根据编译器将结果缓存static在包含类的合成字段中,即B.
原因是类文字在Java 1.1中作为语言特性引入,但字节代码没有改变以对它有特殊支持.
从Java 5开始,类文字被视为实常数,使用单个ldc或ldc_w指令加载到操作数堆栈,就像String文字一样.不同之处在于常量池项的类型,它指的是,String_info为String常数和Class_info为Class常数.
作为旁注,从Java 7开始,Java字节码甚至允许加载类型的常量MethodType或者MethodHandle没有实际的Java语言等价物.
见ldc:
该指数是一个必须是一个有效的索引到当前类(§2.6)的运行时间常量池中一个无符号字节.在运行时常量池项索引要么必须是类型的一个运行时间常数
int或float,或参考为一个字符串文字或符号引用类,方法的类型,或方法手柄(§5.1).如果运行时间常量池项是类型的一个运行时间常数
int或float时,数字值的是运行时间常数的压入操作数栈作为int或float分别.否则,如果运行时常量池条目是表示字符串文字(第5.1节)
reference的类的实例String,那么reference该实例值将被推送到操作数堆栈.否则,如果在运行时常量存储库项是一个符号引用一个类(§5.1),则命名的类被解决(§5.4.3.1)和一个
reference到Class表示类,对象值,被压入的操作数堆.否则,运行时常量池条目必须是方法类型或方法句柄的符号引用(第5.1节).解析了方法类型或方法句柄(第5.4.3.5节),
reference并将得到的java.lang.invoke.MethodTypeorjava.lang.invoke.MethodHandle,value 实例推送到操作数堆栈.
由于您提到了反编译器,大多数反编译器甚至能够识别更复杂的Java 5之前的代码模式并将它们反编译为类文字.当然,简单的ldc指令对于反编译来说是微不足道的.
| 归档时间: |
|
| 查看次数: |
247 次 |
| 最近记录: |