我有以下课程:
public abstract class AClass {
public AClass() {
aMethod();
}
abstract protected void aMethod();
}
public class SubClass extends AClass {
private int x = 5;
private static final int y = 6;
@Override
protected void aMethod() {
System.out.println("x: " + x + " | y: " + y);
}
}
public class Main {
public static void main(String[] args) {
new SubClass();
}
}
Running Main打印以下内容:x:0 | y:6
为什么0会打印x?
答案 0 :(得分:10)
错误行为的原因是错误的初始化序列:
new SubClass()
执行AClass
构造函数AClass
构造函数调用aMethod()
aMethod()
显示x
(目前为0
)和y
,因为静态而6
SubClass
初始化其非静态字段,因此x
变为5
。为避免惊慌失措,从不在构造函数中调用虚拟方法(尤其是覆盖)
答案 1 :(得分:4)
一旦初始化类(加载后),就会初始化静态字段。现在当你打电话给
new SubClass()
发生以下事情。
SubClass
的构造函数被称为SubClass
的第一个语句(隐式)- 调用
的值SuperClass
的构造函数。 - >您正在检查x
此处- 醇>
SuperClass
构造函数执行完成后,初始化SubClass
的实例级字段。因此,x
将在此初始化。
答案 2 :(得分:3)
初始化顺序。在aMethod()
行
private int x = 5
使用像这样的代码示例来学习执行事物的顺序是很好的方法。尝试添加静态和非静态初始化块。
答案 3 :(得分:3)
结果是因为在初始化成员之前调用了超类构造函数。
在您的情况下,执行以下序列:
SubClass
AClass
aMethod()
SubClass
这也是你不应该从构造函数中调用任何可重写方法的原因,因为被调用的方法可以访问未完全初始化的对象的状态。
答案 4 :(得分:1)
private static final int y = 6;
当构造函数调用 aMethod()时,y的值为6,因为它是静态的并且在类加载时被初始化。
private int x = 5;
虽然此初始化附加在构造函数体的末尾。这意味着在执行 aMethod 时,变量x仍具有默认值,即0。
SubClass 的默认构造函数看起来像
SubClass() {
super();
//All instance initialization are performed here.
}
答案 5 :(得分:0)
因为当您创建Subclass
的实例时,它会调用其超类AClass
的构造函数,此时,x
尚未设置为什么它会获取默认值值为0.