1. 如果基類存在默認構造函數,則在子類構造之前,會先調用基類的默認構造函數: view plaincopy to clipboardprint? 01.class A { 02. A() { 03. System.out.println("A create"); 04. } 05.} 06. 07.class B extends A { 08. B() { 09. // 會在這里先調用A的默認構造函數 10. System.out.println("B create"); 11. } 12.} 13. 14.class C extends A { 15. C(int i) { 16. // 會在這里先調用A的默認構造函數 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 3 1.A create 32.C create class A { A() { System.out.println("A create"); } } class B extends A { B() { // 會在這里先調用A的默認構造函數 System.out.println("B create"); } } class C extends A { C(int i) { // 會在這里先調用A的默認構造函數 System.out.println("C create"); } } public class Main { public static void main(String[] args) { B b = new B(); C c = new C(10); } } // 輸出為: A create B create A create C create 2. 如果基類只有帶參數的構造函數,子類必須在自己的構造函數中通過super(...)顯式調用該基類構造函數: view plaincopy to clipboardprint? 01.class A { 02. A(int i) { 03. System.out.println("A create"); 04. } 05.} 06. 07.class B extends A { 08. B() { 09. // 必須在這里顯式調用父類的非默認構造函數,否則編譯不通過 10. // 注意這調用只能放在最前面,否則編譯不通過 11. super(20); 12. System.out.println("B create"); 13. } 14.} 15. 16.class C extends A { 17. C(int i) { 18. // 必須在這里顯式調用父類的非默認構造函數,否則編譯不通過 19. // 注意這調用只能放在最前面,否則編譯不通過 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 class A { A(int i) { System.out.println("A create"); } } class B extends A { B() { // 必須在這里顯式調用父類的非默認構造函數,否則編譯不通過 // 注意這調用只能放在最前面,否則編譯不通過 super(20); System.out.println("B create"); } } class C extends A { C(int i) { // 必須在這里顯式調用父類的非默認構造函數,否則編譯不通過 // 注意這調用只能放在最前面,否則編譯不通過 super(30); System.out.println("C create"); } } public class Main { public static void main(String[] args) { B b = new B(); C c = new C(10); } } // 輸出為: A create B create A create C create 3. 以上只講了最簡單的構造函數調用順序,其實一個對象的真正的初始化過程應該是: 1.將對象的存儲空間初始化為二進制的0. 2.先遞歸到最上層的基類去,將最上層的基類作為當前類。 3.對于當前類: 1.按聲明順序調用成員變量的初始設置代碼。 2.調用構造函數。 4.接著將下一層繼承類作為當前類,繼續步驟3 先看下面的代碼: view plaincopy to clipboardprint? 01.class A { 02. A() { 03. System.out.println("A create"); 04. } 05.} 06. 07.class D { 08. D() { 09. 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.} class A { A() { System.out.println("A create"); } } class D { D() { System.out.println("D create"); } } class B extends A { private D d = new D(); B() { System.out.println("B create"); } } class C extends B { C(int i) { System.out.println("C create"); } } public class Main { public static void main(String[] args) { C c = new C(10); } } 初始化過程大概是這樣的: 1. 先從C遞歸到B,再從B遞歸到A。 2.A沒有成員變量,所以A的構造函數被調用。 3.接到回到B,B有一個D類的成員有初始化,因此D的構造函數被調用。 4.接著B的構造函數被調用。 5.最后回到C,C的構造函數被調用。 所以輸出應該是: A create D create B create C create 4. 必須小心在構造函數中調用虛函數(在JAVA里普通函數都是虛的)的隱患,特別是在基類的構造函數,因為此時繼承類的成員可能還沒有初始完畢: view plaincopy to clipboardprint? 01.class A { 02. A() { 03. System.out.println("A create"); 04. proc(); 05. } 06. public void proc() { 07. } 08.} 09. 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 class A { A() { System.out.println("A create"); proc(); } public void proc() { } } class B extends A { private int i; B() { System.out.println("B create"); i = 10; } public void proc(){ System.out.println(i); } } public class Main { public static void main(String[] args) { B b = new B(); } } 輸出: A create 0 B create A的構造函數調用了proc,此時B的構造函數還沒有被調用,因此i還沒有被賦為10,最終輸出結果是0。 5. 由于Java對象都是通過垃圾回收機制清理對象,因此Java的類沒有析構函數,遇到需要清理類中資源的問題時,可以自己聲明一個函數,如Dispose,在適當的時候調用之 |