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