参考:http://blog.csdn.net/haoel/article/details/4319793
今天看到这篇文章吓了一跳,因为之前看过《Effective C++》,C++在构造函数里调用虚函数的结果是绝对不会将函数下降到子类去执行,即结果不可预测。那java呢?假设我告诉你一个事实:
Java支持在构造函数里调用虚函数
也就是说,在下面的代码中,调用Base()时,会调用Derived::preProcess(),那么最后的输出结果是什么呢?
package com.happyjacket.study;
class Base{
public Base() {
System.out.println("construct Base()");
preProcess();
}
public void preProcess() {
System.out.println("pre process in Base");
}
}
class Member{
public Member(String name) {
System.out.println("construct Member " + name);
}
}
class Derived extends Base {
public String hello = "hello";
public Member member = new Member("jacket");
public Derived() {
// 默认会在一开始调用super();
System.out.println("construct Derived() " + hello);
hello = "initialized in Derived";
}
public void preProcess() {
System.out.println("pre process in Derived");
hello = "modified in Derived...";
}
}
public class Main {
public static void main(String[] args) {
Derived child = new Derived();
System.out.println(child.hello);
}
}
我一开始也以为是这样的(注意第4行):
construct Base()
pre process in Derived
construct Member jacket
construct Derived() modified in Derived...
initialized in Derived
!!!但运行结果却是:
construct Base()
pre process in Derived
construct Member jacket
construct Derived() hello
initialized in Derived
注意第4行!!!以及第3行是在第4行前面的,说明什么呢?
就是非静态成员的初始化时机了,它是发生于调用super()之后(不考虑自行调用super()的情况)而自定义的实体之前的时候。
也就是说,整个流程是这样的:
1. 执行Derived(),会先执行编译器加入的super();
2. 执行Base(),打印第一行;
3. 在Base()里调用preProcess(),执行的是Derived::preProcess(),它打印第二行并将hello的值设置为”modified in Derived…”,Base()调用结束;
4. 回到Derived(),先按成员的声明顺序对各个成员进行初始化,hello的值被设置为”hello”;
5. 执行Derived()自定义的函数体,打印第4行,注意此时hello的值;
6. 最后hello的值被设置为”initialized in Derived”,回到主函数,打印出第5行。
总结一下:
1. Java支持在构造函数里调用(子类相应的)虚函数(其实我觉得挺奇怪的,因为感觉只是重写父类的函数而已,就是虚函数了吗?java里的虚函数就是override吗?)
2. 非静态成员的初始化时机不是在声明的时候,而是在super()执行之后,而执行构造函数自定义的实体之前。