public class Foo {
private int var;
public Foo() {
var = 10;
}
}
在这段代码中,是先给var
赋一个默认值,然后重新赋给10,还是直接赋给10,不赋默认值?
有点微不足道的问题,但我很好奇。
最佳答案
如果您查看 Foo.class
的反编译字节码,您会注意到以下内容:
- 类的构造函数本身只分配值 10(bipush 和 putfield)。该类的构造函数不会先赋值 0 再赋值 10。
- 无论从哪个代码访问,VM 都会将字段的默认值设置为 0。所以这个默认值不会出现在任何地方——至少不会出现在类的字节码中或其他通过反射访问该字段的类中。原始默认值被烘焙到 VM 中。
- 显式设置默认值会产生不同的字节码,参见第二个示例。
.
public class Foo {
private int var;
public Foo();
0 aload_0 [this]
1 invokespecial java.lang.Object() [10]
4 aload_0 [this]
5 bipush 10
7 putfield Foo.var : int [12]
10 return
如果你这样写:
public class Foo {
private int var = 0;
public Foo() {
var = 20;
}
}
字节码将是:
0 aload_0 [this]
1 invokespecial java.lang.Object() [10]
4 aload_0 [this]
5 iconst_0
6 putfield Foo.var : int [12]
9 aload_0 [this]
10 bipush 20
12 putfield Foo.var : int [12]
15 return
下一个例子表明访问变量仍然不会导致任何值的赋值:
public class Foo {
private int var;
public Foo() {
System.out.println(var);
var=10;
}
}
此代码将打印 0
,因为操作码 8 处的 getField Foo.var
会将“0”压入操作数堆栈:
public Foo();
0 aload_0 [this]
1 invokespecial java.lang.Object() [10]
4 getstatic java.lang.System.out : java.io.PrintStream [12]
7 aload_0 [this]
8 getfield Foo.var : int [18]
11 invokevirtual java.io.PrintStream.println(int) : void [20]
14 aload_0 [this]
15 bipush 10
17 putfield Foo.var : int [18]
20 return
关于java - 初始化字段变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4694073/