聊一聊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、调用子类的构造器主体。