我仍在尝试学习 java 类文件格式,并且我知道常量变量值存储在 ConstantValue 属性下,但是我不明白非常量字段值存储在类文件中的位置。如
public Robot robot = new Robot();
我查看了 oracles 类文件规范,但找不到任何这样的属性。
我仍在尝试学习 java 类文件格式,并且我知道常量变量值存储在 ConstantValue 属性下,但是我不明白非常量字段值存储在类文件中的位置。如
public Robot robot = new Robot();
我查看了 oracles 类文件规范,但找不到任何这样的属性。
存储初始值的唯一属性是ConstantValue
. 但是,这仅用于静态变量。在 Java 编译代码中,它仅用于静态最终变量,尽管它可以用于手写字节码中的任何静态变量。当然,该值必须是恒定的。
对于您发布的示例,您拥有 Java 中所谓的initializer。这些在类文件中没有等效项。相反,Java 编译器将在每个超类构造函数调用返回后粘贴此代码。请注意,这意味着如果您可以在此之前查看它们,例如通过在超类构造函数中调用虚拟方法,它们还没有被初始化。
这是一个例子。
public class initializers {
static final float f = 4;
static final int i = int.class.hashCode();
static int i2 = 4;
public final Object x = null;
public Object x2 = null;
public initializers() {}
public initializers(int x) {this();}
public initializers(float x) {}
}
编译和反汇编类结果
.version 49 0
.class super public initializers
.super java/lang/Object
.field static final f F = 4.0F
.field static final i I
.field static i2 I
.field public final x Ljava/lang/Object;
.field public x2 Ljava/lang/Object;
.method public <init> : ()V
.limit stack 2
.limit locals 1
aload_0
invokespecial java/lang/Object <init> ()V
aload_0
aconst_null
putfield initializers x Ljava/lang/Object;
aload_0
aconst_null
putfield initializers x2 Ljava/lang/Object;
return
.end method
.method public <init> : (I)V
.limit stack 1
.limit locals 2
aload_0
invokespecial initializers <init> ()V
return
.end method
.method public <init> : (F)V
.limit stack 2
.limit locals 2
aload_0
invokespecial java/lang/Object <init> ()V
aload_0
aconst_null
putfield initializers x Ljava/lang/Object;
aload_0
aconst_null
putfield initializers x2 Ljava/lang/Object;
return
.end method
.method static <clinit> : ()V
.limit stack 1
.limit locals 0
getstatic java/lang/Integer TYPE Ljava/lang/Class;
invokevirtual java/lang/Object hashCode ()I
putstatic initializers i I
iconst_4
putstatic initializers i2 I
return
.end method
如您所见,f
是唯一一个使用ConstantValue
属性的。i
不是因为它不是一个常量表达式,而i2
不是因为它不是最终的。初始化代码i
并i2
放置在静态初始化程序(“类构造函数”)中。初始化代码x
并x2
粘贴在两个超类构造函数调用之后,但不是在第二个构造函数中,它只调用同一个类中的构造函数。
您粘贴的代码中没有常量。只有一个变量(将在运行时在堆栈上分配)。
如果您对具有非常量字段的类的字节码是什么样子感兴趣,可以试试这篇文章。
该变量robot
在运行时初始化。说,robot
在课堂上Foo
:
class Foo {
public Robot robot = new Robot();
Foo() {
}
}
现在 Java 编译器将转换new Foo()
为执行以下步骤的指令序列:
Foo
在堆上为新对象分配空间。这包括 field 的空间 robot
。Foo
Robot
Foo
Robot
那么字节码中的内容是
Foo
Robot
结论是类文件的字节码中没有字段机器人的空间。有一些分配指令在运行时执行并为堆上的字段创建空间。