初始化字段变量
public class Foo {
private int var;
public Foo() {
var = 10;
}
}
在这段代码中,var
是先被赋予默认值,然后重新被赋予10,还是直接被赋予10而不被赋予默认值?
虽然是一个微不足道的问题,但我很好奇。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果您查看
Foo.class
的反编译字节码,您会注意到以下内容:。
如果您编写以下内容:
字节码将是:
下一个示例显示访问变量仍然不会导致任何值的赋值:
此代码将打印
0
因为操作码 8 处的getField Foo.var
会将“0”压入操作数堆栈:If you look at the decompiled byte code of
Foo.class
, you will notice the following:.
If you write the following:
the bytecode will be:
The next example shows that accessing the variable will still not lead to an assignment of any value:
This code will print
0
becausegetField Foo.var
at opcode 8 will push "0" onto the operand stack:在调用构造函数之前,未初始化的字段将始终被分配默认值,因为运行时将在调用构造函数之前将对象的内存分配归零。它必须这样做,因为它不知道构造函数会提前做什么,并且因为派生类可能存在于其他 jars/类路径中并获取值(如果它受保护)或调用使用该字段之前的方法。由构造函数初始化。
这是独立于编译器执行的,因此这不是编译器可以优化掉的东西,并且编译器甚至无法控制它。
Uninitialized fields will always be assigned the default value prior to calling the constructor, because the runtime will zero the memory allocation for the object prior to calling the constructor. It must do this because it does not know what the constructor might do ahead of time, and because derived classes may live in other jars/classpaths and fetch the value (if it's protected) or call into a method that uses the field before it is initialized by the constructor.
This is performed independently of the compiler, and therefore this is not something the compiler can optimize away, and the compiler doesn't even have control over this.
根据规范:(第 4.2.15 节)
首先是 0,
然后是 10。
如果您首先在构造函数中读取它,您将得到 0。
According to the spec: (Section 4.2.15)
First 0.
Then 10.
If you would read it first in the constructor, you would get 0.
它将首先被赋予默认值。特别是,如果 Foo 派生自 Bar,并且 Bar 的构造函数可以以某种方式获取 var 的值(例如,通过在 Bar 中声明并在 Foo 中重写的虚拟方法),则该默认值将是可见的,即使该变量是最终的。例如:
请注意,即使在声明时对字段进行了初始化,仍然也会发生这种情况:
在这方面,Java 与 C# 不同。在 C# 中,
var
在调用基本构造函数之前会被赋值为 10。It would be given the default value first. In particular, if Foo was derived from Bar, and the constructor of Bar could get at the value of var somehow (e.g. through a virtual method declared in Bar and overridden in Foo), that default value would be visible, even if the variable is final. For example:
Note that this still happens even when the field is initialized at the point of declaration:
In this respect Java differs from C#. In C#,
var
would be assigned the value 10 before the call to the base constructor.分配默认值意味着在您分配默认值之前它已经有一个值。对象在创建时具有默认值,但并未分配该值。
如果查看字节码,唯一的代码就是分配新值。
Assigning the default value implies it had a value before you assigned the default value. An object has the default value when it is created, it is not assigned it.
If you look at the byte code, the only code is to assign the new value.
语言规范说:
然后调用构造函数。
The language specification says:
Then the constructor is called.