1. 如果基類存在預設建構函式,則在子類構造之前,會先調用基類的預設建構函式:
class A {<br /> A() {<br /> System.out.println("A create");<br /> }<br />}</p><p>class B extends A {<br /> B() {<br /> // 會在這裡先調用A的預設建構函式<br /> System.out.println("B create");<br /> }<br />}</p><p>class C extends A {<br /> C(int i) {<br /> // 會在這裡先調用A的預設建構函式<br /> System.out.println("C create");<br /> }<br />}</p><p>public class Main {<br /> public static void main(String[] args) {<br /> B b = new B();<br /> C c = new C(10);<br /> }<br />}</p><p>// 輸出為:<br />A create<br />B create<br />A create<br />C create<br />
2. 如果基類只有帶參數的建構函式,子類必須在自己的建構函式中通過super(...)顯式調用該基類建構函式:
class A {<br /> A(int i) {<br /> System.out.println("A create");<br /> }<br />}</p><p>class B extends A {<br /> B() {<br /> // 必須在這裡顯式調用父類的非預設建構函式,否則編譯不通過<br /> // 注意這調用只能放在最前面,否則編譯不通過<br /> super(20);<br /> System.out.println("B create");<br /> }<br />}</p><p>class C extends A {<br /> C(int i) {<br /> // 必須在這裡顯式調用父類的非預設建構函式,否則編譯不通過<br /> // 注意這調用只能放在最前面,否則編譯不通過<br /> super(30);<br /> System.out.println("C create");<br /> }<br />}</p><p>public class Main {<br /> public static void main(String[] args) {<br /> B b = new B();<br /> C c = new C(10);<br /> }<br />}<br />// 輸出為:<br />A create<br />B create<br />A create<br />C create<br />
3. 以上只講了最簡單的建構函式調用順序,其實一個對象的真正的初始化過程應該是:
- 將對象的儲存空間初始化為二進位的0.
- 先遞迴到最上層的基類去,將最上層的基類作為當前類。
- 對於當前類:
- 按聲明順序調用成員變數的初始設定代碼。
- 調用建構函式。
- 接著將下一層繼承類作為當前類,繼續步驟3
先看下面的代碼:
class A {<br /> A() {<br /> System.out.println("A create");<br /> }<br />}</p><p>class D {<br /> D() {<br /> System.out.println("D create");<br /> }<br />}</p><p>class B extends A {<br /> private D d = new D();<br /> B() {<br /> System.out.println("B create");<br /> }<br />}</p><p>class C extends B {<br /> C(int i) {<br /> System.out.println("C create");<br /> }<br />}</p><p>public class Main {<br /> public static void main(String[] args) {<br /> C c = new C(10);<br /> }<br />}<br />
初始化過程大概是這樣的:
- 先從C遞迴到B,再從B遞迴到A。
- A沒有成員變數,所以A的建構函式被調用。
- 接到回到B,B有一個D類的成員有初始化,因此D的建構函式被調用。
- 接著B的建構函式被調用。
- 最後回到C,C的建構函式被調用。
所以輸出應該是:
A create
D create
B create
C create
4. 必須小心在建構函式中調用虛函數(在JAVA裡普通函數都是虛的)的隱患,特別是在基類的建構函式,因為此時繼承類的成員可能還沒有初始完畢:
class A {<br /> A() {<br /> System.out.println("A create");<br /> proc();<br /> }<br /> public void proc() {<br /> }<br />}</p><p>class B extends A {<br /> private int i;<br /> B() {<br /> System.out.println("B create");<br /> i = 10;<br /> }<br /> public void proc(){<br /> System.out.println(i);<br /> }<br />}</p><p>public class Main {<br /> public static void main(String[] args) {<br /> B b = new B();<br /> }<br />}<br />輸出:<br />A create<br />0<br />B create<br /> A的建構函式調用了proc,此時B的建構函式還沒有被調用,因此i還沒有被賦為10,最終輸出結果是0。
5. 由於Java對象都是通過記憶體回收機制清理對象,因此Java的類沒有解構函式,遇到需要清理類中資源的問題時,可以自己聲明一個函數,如Dispose,在適當的時候調用之。