众所周知,调用子类的构造方法时,系统会先调用父类的构造方法。但是,当父类的构造方法调用了一个public方法A,同时子类又覆写了这个public方法A,初始化子类时,父类调用的是自己的A方法还是子类A方法呢?
答案是:子类的A方法哦。
我相信这个答案会出乎很多人意料,至少我在刚开始运行示例程序时还是难以置信的态度(ps:仔细想想其实也不难理解,毕竟在子类中,父类的A方法已经被覆写)。
咱们先跑一下示例程序,运行结果有惊喜哦。
基类Base:
public class Base {
public void A()
{
System.out.println("run A() in Base");
}
public Base()
{
System.out.println("before run A() in Base()");
A();
System.out.println("after run A() in Base()");
}
}
子类Sub:
public class Sub extends Base{
int r = 1;
@Override
public void A()
{
System.out.println("run A() in Sub r = "+r);
}
public Sub(int ra) {
r = ra;
System.out.println("in Sub r = "+r);
}
}
主类Main:
public class Main {
public static void main(String[] args) {
new Sub(5);
}
}
运行结果:
从结果可见,创建子类对象时,系统先运行了基类Base的构造方法,这个还是符合一般常识的。但是,基类构造方法中调用了子类Sub的A方法,而且子类Sub中的成员变量r不是1,而是0(这篇博客的重点哦,赶紧记下来)!
为什么呢?
首先,基类Base的A方法已经被覆盖,不通过super关键字,常规方法基本无法调用,所以调用子类Sub的A方法才是正常的。
其次,对象的初始化过程为:
1.将分配给对象的存储空间初始化为二进制的0.
2.调用基类的构造方法,此时在构造方法中调用A方法,由于Sub的构造方法未执行,成员变量的赋值也尚未进行,所以r为0.
3.按照声明顺序调用成员变量的构造方法(r此时赋值为1)
4.调用子类的构造方法(r此时赋值为5)
没想到吧,最先执行的不是基类的构造方法,而是默认赋值哦!
总结:构造方法应该只负责初始化工作,调用的方法应该都是private方法,防止方法被子类继承修改,从而造成无法预知的错误。
参考文献
[1].Java编程思想(第4版).埃尔克.北京:机械工业出版社,2007.6:162-164