如何将类文字编译为Java字节码? [英] How is a class literal compiled to Java bytecode?
问题描述
public class A {
}
public class B {
public static void b() {
System.out.println(A.class);
}
}
班级文字如何在.class的字节码中编译的A.class
?它是一个现场参考?我在Oracle / Sun的字节码文档中找不到这一点。
How is the class literal A.class
compiled in B.class's bytecode? Is it a field reference? I can't find a mention of that in the bytecode documentation from Oracle/Sun.
无论是什么原因,反编译器都可以轻松地重建它:
Decompilers have no trouble reconstructing it, whatever it is:
java -jar decompiler.jar B.class
选择JAVA_TOOL_OPTIONS:' - Dfile.encoding = UTF8'
Picked up JAVA_TOOL_OPTIONS: '-Dfile.encoding=UTF8'
-
//
/ /由Procyon编译v0.5.30
//
// // Decompiled by 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
。
Before Java 5, a class literal like A.class
was just syntactic sugar for calling Class.forName("A")
under the hood, translating a ClassNotFoundException
to a NoClassDefFoundError
and, depending on the compiler, cache the result in a synthetic static
field of the containing class, i.e. B
.
原因是在Java 1.1中引入了类文字作为语言功能,但字节代码没有更改为对它有特殊支持。
The reason is that class literals were introduced in Java 1.1 as a language feature, but the byte code was not changed to have special support for it.
从Java 5开始,类文字被视为实常数,使用单个 ldc
或 ldc_w加载到操作数堆栈
指令,就像 String
literals一样。不同之处在于常量池项的类型,它指的是字符串常量和 Class_info
for Class
常量。
Since Java 5, class literals are treated as real constants, being loaded to the operand stack using a single ldc
or ldc_w
instruction, just like with String
literals. The difference lies in the type of the constant pool item, it refers to, String_info
for String
constants and Class_info
for Class
constants.
作为旁注,从Java 7开始,Java字节码甚至允许加载 <$ c $类型的常量c> MethodType 或 MethodHandle
,它没有等效的实际Java语言。
As a side note, since Java 7, the Java bytecode even allows to load constants of type MethodType
or MethodHandle
which has no actual Java language equivalent.
参见 ldc
:
index 是一个无符号字节,必须是当前类(第2.6节)的运行时常量池的有效索引。 index 处的运行时常量池条目必须是类型
int
或float 的运行时常量
,或对字符串文字的引用,或对类,方法类型或方法句柄的符号引用(第5.1节)。
The index is an unsigned byte that must be a valid index into the run-time constant pool of the current class (§2.6). The run-time constant pool entry at index either must be a run-time constant of type
int
orfloat
, or a reference to a string literal, or a symbolic reference to a class, method type, or method handle (§5.1).
如果运行时常量池条目是类型 int
或 float
的运行时常量,数字值该运行时常量的分别作为 int
或 float
推送到操作数堆栈。
If the run-time constant pool entry is a run-time constant of type int
or float
, the numeric value of that run-time constant is pushed onto the operand stack as an int
or float
, respectively.
否则,如果运行时常量池条目是引用
到类<$ c $的实例c> String 表示字符串文字(第5.1节),然后推送引用
到该实例 value 在操作数堆栈上。
Otherwise, if the run-time constant pool entry is a reference
to an instance of class String
representing a string literal (§5.1), then a reference
to that instance, value, is pushed onto the operand stack.
否则,如果运行时常量池条目是对类的符号引用(第5.1节),则命名类被解析(§ 5.4.3.1)和参考
到 Cl ass
表示该类的对象 value 被推送到操作数堆栈。
Otherwise, if the run-time constant pool entry is a symbolic reference to a class (§5.1), then the named class is resolved (§5.4.3.1) and a reference
to the Class
object representing that class, value, is pushed onto the operand stack.
否则,运行时常量池条目必须是方法类型或方法句柄的符号引用(第5.1节)。方法类型或方法句柄被解析(第5.4.3.5节)和引用
到 java.lang.invoke.MethodType的结果实例
或 java.lang.invoke.MethodHandle
,value被推送到操作数堆栈。
Otherwise, the run-time constant pool entry must be a symbolic reference to a method type or a method handle (§5.1). The method type or method handle is resolved (§5.4.3.5) and a reference
to the resulting instance of java.lang.invoke.MethodType
or java.lang.invoke.MethodHandle
, value, is pushed onto the operand stack.
由于您提到了反编译器,大多数反编译器甚至能够识别更复杂的Java 5之前的代码模式并将它们反编译为类文字。当然,简单的 ldc
指令对于反编译来说是微不足道的。
Since you mentioned decompilers, most decompilers are even capable of recognizing the more complex pre-Java 5 code patterns and decompile them to a class literal. Of course, the simple ldc
instruction is trivial to decompile.
这篇关于如何将类文字编译为Java字节码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!