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

Jim*_*ter 4 java bytecode

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'

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

    public class B
    {
        public static void b() {
            System.out.println(A.class); <<<
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 7

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

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

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

作为旁注,从Java 7开始,Java字节码甚至允许加载类型的常量MethodType或者MethodHandle没有实际的Java语言等价物.

ldc:

指数是一个必须是一个有效的索引到当前类(§2.6)的运行时间常量池中一个无符号字节.在运行时常量池项索引要么必须是类型的一个运行时间常数intfloat,或参考为一个字符串文字或符号引用类,方法的类型,或方法手柄(§5.1).

如果运行时间常量池项是类型的一个运行时间常数intfloat时,数字的是运行时间常数的压入操作数栈作为intfloat分别.

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

否则,如果在运行时常量存储库项是一个符号引用一个类(§5.1),则命名的类被解决(§5.4.3.1)和一个referenceClass表示类,对象,被压入的操作数堆.

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

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