当从super()运行方法时,为什么字段没有初始化为非默认值?

Smi*_*mig 8 java inheritance

我一定花了一个多小时试图找出出现意外行为的原因.我最终意识到没有像我期望的那样设置场地.在耸耸肩并继续前进之前,我想明白为什么会这样.

在运行下面的示例时,我希望输出为true,但它是错误的.其他测试表明,我总是得到任何类型的默认值.

public class ClassOne {

    public ClassOne(){
        fireMethod();
    }

    protected void fireMethod(){
    }

}

public class ClassTwo extends ClassOne {

    boolean bool = true;

    public ClassTwo() {
        super();
    }

    @Override
    protected void fireMethod(){
        System.out.println("bool="+bool);
    }

    public static void main(String[] args) {
        new ClassTwo();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

bool=false
Run Code Online (Sandbox Code Playgroud)

sp0*_*00m 7

boolean bool = true;

public ClassTwo() {
    super();
}
Run Code Online (Sandbox Code Playgroud)

是完全相同的

boolean bool;

public ClassTwo() {
    super();
    bool = true;
}
Run Code Online (Sandbox Code Playgroud)

编译器自动在构造函数中移动字段初始化(在超级构造函数调用之后,隐式或显式).

由于布尔字段默认值是false,当super()被称为(因此ClassOne()fireMethod()),bool还没有被设置为true呢.


有趣的事实:以下构造函数

public ClassTwo() {
    super();
    fireMethod();
}
Run Code Online (Sandbox Code Playgroud)

将被理解为

public ClassTwo() {
    super();
    bool = true;
    fireMethod();
}
Run Code Online (Sandbox Code Playgroud)

由JVM,因此输出将是

bool=false
bool=true
Run Code Online (Sandbox Code Playgroud)


ass*_*ias 5

在子类构造函数之前调用超类构造函数.在Java中,在运行构造函数之前,所有实例成员都有其默认值(false,0,null).因此,当super()被调用时,bool仍然是假的(布尔值的默认值).

更一般地说,从构造函数(在ClassOne中)调用可覆盖的方法是一个坏主意,因为您刚刚发现:您最终可能还在处理尚未完全初始化的对象.