Java構造時成員初始化的陷阱(Java中的聲明和初始化不是一個原子操做)


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);

}
} 函數


  1. 進入Derived 構造函數。
  2. Derived 成員變量的內存被分配。
  3. Base 構造函數被隱含調用。
  4. Base 構造函數調用preProcess()。
  5. Derived 的preProcess 設置whenAmISet 值爲 "set in preProcess()"。
  6. Derived 的成員變量初始化被調用。
  7. 執行Derived 構造函數體

等一等,這怎麼可能?在第6步,Derived 成員的初始化竟然在 preProcess() 調用以後?是的,正是這樣,咱們不能讓成員變量的聲明和初始化變成一個原子操做,雖然在Java中咱們能夠把其寫在一塊兒,讓其看上去像是聲明和初始化一體。但這只是假象,咱們的錯誤就在於咱們把Java中的聲明和初始化當作了一體在C+的世界中,C並不支持成員變量在聲明的時候進行初始化,其須要你在構造函數中顯式的初始化其成員變量的值,看起來很土,但其實C+用心良苦。
在面向對象的世界中,由於程序以對象的形式出現,致使了咱們對程序執行的順序霧裏看花。因此,在面向對象的世界中,程序執行的順序至關的重要
下面是對上面各個步驟的逐條解釋。 spa

  1. 進入構造函數。
  2. 爲成員變量分配內存。
  3. 除非你顯式地調用super(),不然Java 會在子類的構造函數最前面偷偷地插入super() 。
  4. 調用父類構造函數。
  5. 調用preProcess,由於被子類override,因此調用的是子類的。
  6. 因而,初始化發生在了preProcess()以後。這是由於,Java須要保證父類的初始化早於子類的成員初始化,不然,在子類中使用父類的成員變量就會出現問題。
  7. 正式執行子類的構造函數(固然這是一個空函數,雖然咱們沒有聲明)。
相關文章
相關標籤/搜索