class Base
{
Base() {
System.out.println("1");
preProcess();
}
void preProcess() {
System.out.println("2");
}
}
public class Test extends Base
{
public String whenAmISet = "set when declared";
@Override void preProcess()
{
System.out.println("3");
whenAmISet = "set in preProcess()";
}
} ide
public class Main{
public static void main(String[] args) {
Test d = new Test();
System.out.println(d.whenAmISet);
}
} 函數
- 進入Derived 構造函數。
- Derived 成員變量的內存被分配。
- Base 構造函數被隱含調用。
- Base 構造函數調用preProcess()。
- Derived 的preProcess 設置whenAmISet 值爲 "set in preProcess()"。
- Derived 的成員變量初始化被調用。
- 執行Derived 構造函數體
等一等,這怎麼可能?在第6步,Derived 成員的初始化竟然在 preProcess() 調用以後?是的,正是這樣,咱們不能讓成員變量的聲明和初始化變成一個原子操做,雖然在Java中咱們能夠把其寫在一塊兒,讓其看上去像是聲明和初始化一體。但這只是假象,咱們的錯誤就在於咱們把Java中的聲明和初始化當作了一體。在C+的世界中,C並不支持成員變量在聲明的時候進行初始化,其須要你在構造函數中顯式的初始化其成員變量的值,看起來很土,但其實C+用心良苦。
在面向對象的世界中,由於程序以對象的形式出現,致使了咱們對程序執行的順序霧裏看花。因此,在面向對象的世界中,程序執行的順序至關的重要。
下面是對上面各個步驟的逐條解釋。 spa
- 進入構造函數。
- 爲成員變量分配內存。
- 除非你顯式地調用super(),不然Java 會在子類的構造函數最前面偷偷地插入super() 。
- 調用父類構造函數。
- 調用preProcess,由於被子類override,因此調用的是子類的。
- 因而,初始化發生在了preProcess()以後。這是由於,Java須要保證父類的初始化早於子類的成員初始化,不然,在子類中使用父類的成員變量就會出現問題。
- 正式執行子類的構造函數(固然這是一個空函數,雖然咱們沒有聲明)。