Java語言基礎:對象的初始化

1.  如果基類存在默認構造函數(shù),則在子類構造之前,會先調(diào)用基類的默認構造函數(shù):

  1. class A {  
  2.     A() {  
  3.         System.out.println("A create");  
  4.     }  
  5. }  
  6.    
  7. class B extends A {  
  8.     B() {  
  9.         // 會在這里先調(diào)用A的默認構造函數(shù)   
  10.         System.out.println("B create");  
  11.     }  
  12. }  
  13.    
  14. class C extends A {  
  15.     C(int i) {  
  16.         // 會在這里先調(diào)用A的默認構造函數(shù)   
  17.         System.out.println("C create");  
  18.     }  
  19. }  
  20.    
  21. public class Main {              
  22.     public static void main(String[] args) {  
  23.         B b = new B();  
  24.         C c = new C(10);  
  25.     }  
  26. }  
  27.    
  28. // 輸出為:   
  29. A create  
  30. B create  
  31. A create  
  32. C create  

 

 

 

2.  如果基類只有帶參數(shù)的構造函數(shù),子類必須在自己的構造函數(shù)中通過super(...)顯式調(diào)用該基類構造函數(shù):

 

  1. class A {  
  2.     A(int i) {  
  3.         System.out.println("A create");  
  4.     }  
  5. }  
  6.    
  7. class B extends A {  
  8.     B() {  
  9.         // 必須在這里顯式調(diào)用父類的非默認構造函數(shù),否則編譯不通過   
  10.         // 注意這調(diào)用只能放在最前面,否則編譯不通過   
  11.         super(20);  
  12.         System.out.println("B create");  
  13.     }  
  14. }  
  15.    
  16. class C extends A {  
  17.     C(int i) {  
  18.         // 必須在這里顯式調(diào)用父類的非默認構造函數(shù),否則編譯不通過   
  19.         // 注意這調(diào)用只能放在最前面,否則編譯不通過   
  20.         super(30);  
  21.         System.out.println("C create");  
  22.     }  
  23. }  
  24.    
  25. public class Main {              
  26.     public static void main(String[] args) {  
  27.         B b = new B();  
  28.         C c = new C(10);  
  29.     }  
  30. }  
  31. // 輸出為:   
  32. A create  
  33. B create  
  34. A create  
  35. C create  

 

3.  以上只講了最簡單的構造函數(shù)調(diào)用順序,其實一個對象的真正的初始化過程應該是:

  1. 將對象的存儲空間初始化為二進制的0.
  2. 先遞歸到最上層的基類去,將最上層的基類作為當前類。
  3. 對于當前類:
    1. 按聲明順序調(diào)用成員變量的初始設置代碼。
    2. 調(diào)用構造函數(shù)。
  4. 接著將下一層繼承類作為當前類,繼續(xù)步驟3

     

    先看下面的代碼:

    1. class A {  
    2.     A() {  
    3.         System.out.println("A create");  
    4.     }  
    5. }  
    6.    
    7. class D {  
    8.     D() {  
    9.         System.out.println("D create");  
    10.     }  
    11. }  
    12.    
    13. class B extends A {  
    14.     private D d = new D();  
    15.     B() {  
    16.         System.out.println("B create");  
    17.     }  
    18. }  
    19.    
    20. class C extends B {  
    21.     C(int i) {  
    22.         System.out.println("C create");  
    23.     }  
    24. }  
    25.    
    26. public class Main {              
    27.     public static void main(String[] args) {  
    28.         C c = new C(10);  
    29.     }  
    30. }  
     

     

    初始化過程大概是這樣的:

    1.  先從C遞歸到B,再從B遞歸到A。
    2. A沒有成員變量,所以A的構造函數(shù)被調(diào)用。
    3. 接到回到B,B有一個D類的成員有初始化,因此D的構造函數(shù)被調(diào)用。
    4. 接著B的構造函數(shù)被調(diào)用。
    5. 最后回到C,C的構造函數(shù)被調(diào)用。

      所以輸出應該是:

      A create

      D create

      B create

      C create

       

      4.  必須小心在構造函數(shù)中調(diào)用虛函數(shù)(在JAVA里普通函數(shù)都是虛的)的隱患,特別是在基類的構造函數(shù),因為此時繼承類的成員可能還沒有初始完畢:

      1. class A {  
      2.     A() {  
      3.         System.out.println("A create");  
      4.         proc();  
      5.     }  
      6.     public void proc() {  
      7.     }  
      8. }  
      9.    
      10. class B extends A {  
      11.     private int i;  
      12.     B() {  
      13.         System.out.println("B create");  
      14.         i = 10;  
      15.     }  
      16.     public void proc(){  
      17.         System.out.println(i);  
      18.     }  
      19. }  
      20.    
      21. public class Main {              
      22.     public static void main(String[] args) {  
      23.         B b = new B();  
      24.     }  
      25. }  
      26. 輸出:  
      27. A create  
      28. 0  
      29. B create  
       
      A的構造函數(shù)調(diào)用了proc,此時B的構造函數(shù)還沒有被調(diào)用,因此i還沒有被賦為10,最終輸出結果是0。

       

       

      5.  由于Java對象都是通過垃圾回收機制清理對象,因此Java的類沒有析構函數(shù),遇到需要清理類中資源的問題時,可以自己聲明一個函數(shù),如Dispose,在適當?shù)臅r候調(diào)用之。