Java 其中是存储在类文件中的变量的初始值
我仍在尝试学习java类文件格式,我知道常量变量值存储在ConstantValue属性下,但是我不知道非常量字段值存储在类文件中的什么位置。比如Java 其中是存储在类文件中的变量的初始值,java,bytearray,field,.class-file,Java,Bytearray,Field,.class File,我仍在尝试学习java类文件格式,我知道常量变量值存储在ConstantValue属性下,但是我不知道非常量字段值存储在类文件中的什么位置。比如 public Robot robot = new Robot(); 我查看了oracles类文件规范,但找不到任何类似的属性 粘贴的代码中没有常量。只有一个变量(将在运行时在堆栈上分配) 如果您对具有非常量字段的类的字节码有兴趣,可以尝试 变量robot在运行时初始化。比如说,robot正在上课Foo: class Foo { public
public Robot robot = new Robot();
我查看了oracles类文件规范,但找不到任何类似的属性 粘贴的代码中没有常量。只有一个变量(将在运行时在堆栈上分配) 如果您对具有非常量字段的类的字节码有兴趣,可以尝试
变量
robot
在运行时初始化。比如说,robot
正在上课Foo
:
class Foo {
public Robot robot = new Robot();
Foo() {
}
}
现在,Java编译器将new Foo()
转换为一系列指令,执行以下步骤:
- 为堆上的新对象
分配空间。这包括字段Foo
的空间robot
- 跳转到类
Foo
- Foo初始值设定项为
Robot的新实例分配空间
- 调用
Foo的父级构造函数
- 调用
机器人的初始值设定项
- Foo初始值设定项为
Foo的分配和初始化说明
机器人的分配和初始化说明
存储初始值的唯一属性是
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
.version 49 0
.class超级公共初始值设定项
.super java/lang/Object
.现场静态最终f=4.0F
.field静态期末考试i
.现场静态i2 I
.field public final x Ljava/lang/Object;
.field public x2 Ljava/lang/Object;
.public方法:()V
.限制堆栈2
.限制本地人1
阿洛德0
调用特殊的java/lang/Object()V
阿洛德0
空的
putfield初始值设定项x Ljava/lang/Object;
阿洛德0
空的
putfield初始化器x2 Ljava/lang/Object;
返回
.结束方法
.方法:(一)五
.限制堆栈1
.限制本地人2
阿洛德0
调用特殊初始值设定项()V
返回
.结束方法
公共方法:(F)V
.限制堆栈2
.限制本地人2
阿洛德0
调用特殊的java/lang/Object()V
阿洛德0
空的
putfield初始值设定项x Ljava/lang/Object;
阿洛德0
空的
putfield初始化器x2 Ljava/lang/Object;
返回
.结束方法
.静态方法:()V
.限制堆栈1
.限制本地值0
getstatic java/lang/Integer类型Ljava/lang/Class;
invokeVirtualJava/lang/Object hashCode()I
putstatic初始值设定项i
iconst_4
putstatic初始值设定项i2 I
返回
.结束方法
如您所见,
f
是唯一使用ConstantValue
属性的i
没有,因为它不是一个常量表达式,而i2
没有,因为它不是最终表达式。初始化i
和i2
的代码放在静态初始值设定项(“类构造函数”)中。初始化x
和x2
的代码是在两个超类构造函数调用后粘贴的,但不在第二个构造函数中,后者只调用同一类中的构造函数。因为值如果不是常量,它不能存储在类文件中。但该变量何时初始化,则错误的变量将存储在堆栈或堆中,具体取决于声明它的位置。如果它是一个方法局部变量,那么只有它会进入堆栈,否则它会进入堆。@JunedAhsan这个问题是关于字段的,所以我假设它是一个字段,而不是局部变量。我还对答案补充了一些解释