使用多态的情况下初始化全过程


在基类的构造器中要尽量避免调用可能被继承重写的方法,否则在初始化时将会引发意外

一个动态绑定的方法调用会深入到继承层次的结构中,它可以调用导出类中的方法,如果在基类的构造器中这样做,就可能会调用某个方法,而这个方法所操纵的成员可能还未进行初始化:

class Glyph{
    void draw(){
        print("Glyph.draw()");   //这个方法其实并未被调用
    }
    Glyph{
        print("Glyph() bfore draw()");
        draw();     //就是在这个地方,调用了可能在导出类中重写的方法,将可能导致意外结果
        print("Glyph() after draw()");
    }
}

class RoundGlyph extends Glyph{
    private int radius = 1;
    RoundGlyph(int r){
        radius = r;
        print("RoundGlyph.RounGlyph(), radius=" + radius);
    }
    void draw(){
        print("RoundGlyph.draw(), radius = "+ radius);   //基类在构造时实际调用的是此方法
    }
}

public class Test(){
    public static void main(String[] args){
        new RoundGlyph(5);      //初始化过程会先调用基类的构造器,基类初始化完成后才会进行导出类的初始化
    }
}

/*
output:
Glyph() before draw()     
RoundGlyph.draw(), radius = 0     //调用了导出类中的方法,但相关参数在子类中,还未初始化
Glyph() after draw()
RoundGlyph.RounGlyph(), radius= 5  //最后才是进行导出类的初始化
*/

在使用继承以及多态时的初始化过程:

1)在任何事件发生之前,将分配给对象的存储空间初始化成二进制的零

2)调用基类构造器。如果此时调用了被重写的方法,用于步骤一的缘故,方法中使用的变量值为0

3)按照声明的顺序调用成员的初始化方法

4)调用导出类的构造器主体

注: 若导出类中的方法通过“组合”方式嵌入了一个类内部的对象的引用,其值就是null

总结:


在编写构造器时,需要尽可能用简单的方法使对象进入正常状态,尽量避免调用其他方法。

在构造器中能够安全调用的只有基类中的final方法(也适用于private方法,它们自动属于final方法)。这些方法不能被覆盖,因此才是安全的。


你可能感兴趣的:(使用多态的情况下初始化全过程)