我仍在尝试学习java类文件格式,并且我理解常量变量值存储在ConstantValue属性下,但是我不明白非常量字段值存储在类文件中的位置。如
public Robot robot = new Robot();
我查看了oracles类文件规范,但我找不到这样的任何属性。
答案 0 :(得分:2)
存储初始值的唯一属性是ConstantValue
。但是,这仅用于静态变量。在Java编译代码中,它仅用于静态最终变量,尽管它可以用于手写字节码中的任何静态变量。当然,价值必须是恒定的。
对于您发布的示例,您将Java中称为初始化程序的内容。这些在类文件中没有等价物。相反,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
的代码在两个超类构造函数调用之后粘贴,但不在第二个构造函数中粘贴,后者只调用同一个类中的构造函数。
答案 1 :(得分:0)
您粘贴的代码中没有常量。只有一个变量(在运行时将在堆栈上分配)。
如果您对具有非常量字段的类的字节码感兴趣,可以尝试this article。
变量robot
在运行时初始化。比如,robot
在课程Foo
中:
class Foo {
public Robot robot = new Robot();
Foo() {
}
}
现在,Java编译器会将new Foo()
转换为执行以下步骤的指令序列:
Foo
分配空间。 这包括字段空间 robot
。Foo
的初始化程序说明
Robot
Foo
Robot
那么字节码中的内容是
Foo
Robot
结论是类文件中的字节码中没有字段机器人的空间。有一些分配指令在运行时执行,并为堆上的字段创建空间。