温故而知新の构造函数

seven 2020年11月06日 362次浏览

聊一聊java中的构造函数

今天看书看到一段挺有意思的代码,看完觉得对于学习java的构造函数这块有了更新的理解,突然有种温故而知新的感觉,特地做个笔记出来,以免之后忘记。代码相对比较简单:

public class PolyConstructors {
    public static void main(String[] args) {
        new RoundGlyph(2);
    }
}
class Glyph {
    void draw() {
        print("Glyph.draw()");
    }
    Glyph() {
        print("Glyph() before draw()");
        draw();
        print("Glyph() after draw()");
    }
    static void print(Object object) {
        System.out.println(object);
    }
}
class RoundGlyph extends Glyph {
    private int radius = 1;
    RoundGlyph(int i) {
        radius = i;
        print("RoundGlyph.RoundGlyph(), radius=" + radius);
    }
    @Override
    void draw() {
        print("RoundGlyph.draw(). radius=" + radius);
    }
}

运行结果如下:

Glyph() before draw()
RoundGlyph.draw(). radius=0
Glyph() after draw()
RoundGlyph.RoundGlyph(), radius=2

这里我们先捋一捋调用顺序,new一个RoundGlyph时先初始化Glyph并调用了Glyph.draw(),然而由于draw方法被@Override此时应该调用RoundGlyph.draw(),让我困惑的就是这里radius的输出值是0而不是我们的初始值1,如果读者跟我有同样困惑,说明对构造函数的理解还不够深入,下面是构造函数初始化顺序的解读--摘自《java编程思想》多态一节:
1、java的构造函数顺序跟类加载的顺序一致,先调用某个类的构造函数,如果该类有基类的话会先调用基类的构造函数,如果还有超级父类,依次调用,父类完成后再依次从父级到子级依次调用。
2、在其他任何事物发生之前,将分配给对象的存储空间初始化为二进制的0。
3、如上面的构造函数一样,调用被覆盖的draw时,此时RoundGlyph实际上还没初始化完,所以成员变量的值为0(这个是这次get到的新的知识点)。
4、按照声明的顺序调用成员的初始化方法。
5、调用子类的构造器主体。