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

时间:2017-08-22 18:42:58

标签: java bytecode

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

1 个答案:

答案 0 :(得分:7)

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

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

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

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

请参阅ldc

  

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

     

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

     

否则,如果运行时常量池条目是表示字符串文字(第5.1节)的类reference的实例的String,那么该实例的reference value ,被压入操作数堆栈。

     

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

     

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

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