Java 为什么';我的字段是否初始化为我给它的值
我有以下课程:Java 为什么';我的字段是否初始化为我给它的值,java,Java,我有以下课程: 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 p
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();
}
}
运行Main打印以下内容:x:0 | y:6
为什么要为x打印0?因为当您创建
子类的实例时,它会调用其超类AClass
的构造函数,此时,x
尚未设置,这就是为什么它会获得默认值0的原因。初始化顺序aMethod()
在行private int x=5之前调用
使用类似这样的代码示例是了解执行顺序的一种很好的方法。尝试添加静态和非静态初始化块。初始化类后(加载后),静态字段立即初始化。现在当你打电话时
newsubclass()
发生以下情况
子类
的构造函数被称为子类
的第一条语句(隐式)
调用了超类的构造函数。-->您正在此处检查x
的值
一旦超类
构造函数的执行完成,则初始化子类
的实例级字段。因此,x
将在此处初始化
错误行为的原因是错误的初始化顺序:
newsubclass()
执行AClass
构造函数
AClass
构造函数调用aMethod()
aMethod()
子类
初始化其非静态字段,使x
变为5
为了避免意外,永远不要在构造函数中调用虚拟方法(特别是重写方法)结果是,在初始化成员之前调用了超类构造函数
private static final int y = 6;
在您的情况下,执行以下顺序:
- 调用构造函数
子类
- 立即调用构造函数
AClass
- 方法调用
aMethod()
- 初始化
子类的成员
这也是为什么不应从构造函数调用任何可重写方法的原因,因为被调用的方法可能访问未完全初始化的对象的状态
private static final int y = 6;
当构造函数调用aMethod()时,y的值为6,因为它是静态的,并且在类加载时初始化
private int x = 5;
而此初始化附加在构造函数主体的末尾。这意味着在执行aMethod时,变量x仍然具有默认值,即0
子类的默认构造函数如下所示
SubClass() {
super();
//All instance initialization are performed here.
}
我猜在初始化子类的私有成员x之前,会调用基类构造函数。(我的Java有点生疏了)但是所有的方法在Java中都是虚拟的,不是吗?但是,并非所有方法都是可重写的。@安德鲁·斯宾塞:是的,默认情况下Java方法是虚拟的(您可以声明非虚拟的final
方法),如果您对虚拟性采用纯技术定义,甚至final
Java方法也是虚拟的(它们是后期绑定的,忽略了优化)。但我更喜欢你的思考方式——毕竟,重要的是“最终”结果,即无法覆盖。