Java constructor vs inline field initialisation
如果我有以下代码:
1 2 3 4 5 6 7 8 9 10
| public class Test {
private int x = 5;
private static int y = 5;
public Test() {
x = 10;
y = 10;
}
} |
我想知道,在这两种情况下,它最初是否会分配5,然后用10更新这个值,换句话说,没有点在内联和构造函数中初始化变量,因为它实际上有两次初始化变量的效果?或者在x(作为一个实例字段)的情况下,它是否只是用x=10替换x=5,因此只运行x=10?
了解反编译版本会很高兴。
I'm wondering in both cases will it actually initially assign 5, and then update this with 10
号
对。施工单位将:
呼叫super()。
执行任何内联初始化和匿名初始化块。
执行构造函数的其余主体。
这在JLS 12.5-6中有更详细的说明。
编译器不会进行这种优化——实际上没有必要进行这种微优化(您可以确保使用javap)。
此外,语言规范还规定了这些值的分配顺序。这些步骤在逻辑上应该是不同的步骤,而不是组合在一起的。
当jvm加载类时,它实际上加载test.class并为静态变量(如y)分配内存。任何成员变量(如x)都只能在构造new test()之类的对象时初始化;
- 不。值在构造函数运行时初始化,每个实例一次。
- 在构造函数运行之前,当jvm加载类时,jvm是否为x、y分配内存?只能是静态变量,在这种情况下是y。
- @EJP成员变量(如x)将仅在new test()时初始化,对吗?编辑了我的答案。
- 例如,当调用new时,会分配变量空间。
- 通过实例变量,你的意思是成员变量对吗?我同意。但是,当JVM加载类时,或者在类准备好构造之前,类中的静态变量(如Y)以及静态块都会被初始化。
- 错了。我是认真的。ME和JLS使用的术语是"实例变量"。"成员变量"不可接受,因为它包含静态成员。
- 我不是来争论的。我真的想知道静态变量是如何初始化的,请看这里。它说:静态变量在加载类时被初始化。类中的静态变量在创建该类的任何对象之前被初始化。类中的静态变量在类的任何静态方法运行之前初始化。如果我错了,请给我指出正确的资源。
- 你不能在这里引用初学者的书。请参阅我的答案中引用的JLS部分。
简单流程是:1。父类初始化2。静态字段和静态节按照它们在源文件中出现的顺序进行初始化三。字段初始化和实例节按照它们在源文件中出现的顺序初始化4。构造函数执行
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class TestClass {
private int a = 5;
{
a = 10;
}
private static int b = 10;
static {
b = 15;
}
public TestClass () {
System. out. println(a +"," + b );
a = 20;
b = 30;
System. out. println(a +"," + b );
}
public static void main (String args []) {
TestClass t = new TestClass ();
}
} |
输出:
号
- 不正确。构造函数执行包括调用super()、变量和匿名实例初始值设定项,然后调用其自身代码的其余部分。
- 不完全正确:如果我们有一个基类,那么链将是:1。基类static init(bot成员和节);2.当前类静态初始化;3.基类实例成员init(booth成员和节);4.基类构造函数;5.当前类即时成员初始化;6。当前类构造函数。
- 再次不正确。调用super()省略了初始化基类的所有内容,但要详细说明:(a)调用当前类的构造函数,其第一个操作是调用基类的构造函数,(b)调用基类的super(),(c)调用基类的实例变量和匿名初始值设定项,(d)调用其余的基类的构造函数,(e)从基类的构造函数返回到当前类的构造函数,(f)调用当前类的实例变量和匿名初始值设定项,…
- 在字节码方面-是的,你是对的。所有初始化都发生在(构造函数)中。我的解释不太清楚。通过构造函数的执行,我指的是构造函数内部的"代码",而不是构造函数本身的调用。
当使用这样的赋值语句声明变量时,该值将成为该变量的默认值。如果不更改它,它将始终返回该值。如果覆盖默认值,它将返回新值。