存储在类文件中的变量的初始值在哪里

时间:2013-06-02 14:41:06

标签: java bytearray field .class-file

我仍在尝试学习java类文件格式,并且我理解常量变量值存储在ConstantValue属性下,但是我不明白非常量字段值存储在类文件中的位置。如

public Robot robot = new Robot();

我查看了oracles类文件规范,但我找不到这样的任何属性。

2 个答案:

答案 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没有,因为它不是最终的。初始化ii2的代码放在静态初始化程序('类构造函数')中。初始化xx2的代码在两个超类构造函数调用之后粘贴,但不在第二个构造函数中粘贴,后者只调用同一个类中的构造函数。

答案 1 :(得分:0)

您粘贴的代码中没有常量。只有一个变量(在运行时将在堆栈上分配)。

如果您对具有非常量字段的类的字节码感兴趣,可以尝试this article


变量robot在运行时初始化。比如,robot在课程Foo中:

class Foo {
    public Robot robot = new Robot();
    Foo() {
    }
}

现在,Java编译器会将new Foo()转换为执行以下步骤的指令序列:

  • 在堆上为新对象Foo分配空间。 这包括字段空间 robot
  • 跳转到课程Foo的初始化程序说明
    • Foo初始值设定项为Robot
    • 的新实例分配空间
    • 调用Foo
    • 之父的构造函数
    • 调用Robot
    • 的初始值设定项
  • ...

那么字节码中的内容是

  • Foo
  • 的分配和初始化说明
  • Robot
  • 的分配和初始化说明

结论是类文件中的字节码中没有字段机器人的空间。有一些分配指令在运行时执行,并为堆上的字段创建空间。