這篇文章帶給大家的內容是關於Java基類構造器呼叫的講解(附程式碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
在《Java程式設計思想》第7章復用類別中有這樣一段話,值得深思。當子類別繼承了父類別時,就涉及了基底類別和導出類別(子類別)這兩個類別。從外部來看,導出類別就像是與基底類別有相同介面的新類別,或許還會有一些額外的方法和領域。但繼承不只是複製基底類別的介面。當創建一個導出類別對象時,該對象包含了一個基類的子對象,這個子對象與你用基類直接創建的對像是一樣的,二者區別在於,後者來自於外部,而基類的子物件是被包裹在導出類別物件內部。
這就引發出了一個很重要的問題,對基底類別子物件的正確初始化也是至關重要的(我們可能在子類別的使用基底類別中繼承的方法和領域),而且也只有一種方法來保證這一點:在子類別建構器中呼叫基底類別建構器來執行初始化。
我們知道,當一個類別你沒有給他建構函數,Java會自動幫你呼叫無參的建構器,同時Java也會在匯出類別的構造器中插入對基類構造器的呼叫。下面的程式碼說明了這個工作機制:
//: reusing/Cartoon.java // Constructor calls during inheritance. import static net.mindview.util.Print.*; class Art { Art() { print("Art constructor"); } } class Drawing extends Art { Drawing() { print("Drawing constructor"); } } public class Cartoon extends Drawing { public Cartoon() { print("Cartoon constructor"); } public static void main(String[] args) { Cartoon x = new Cartoon(); } } /* Output: Art constructor Drawing constructor Cartoon constructor *///:~
觀察上述程式碼的運行結果,在創建Cartoon物件時,會先呼叫其父類Drawing的建構器,而其父類又繼承自Art類,所以又會呼叫Art類別的構造器,就像層層往上。雖然在其構造器中都沒有明確地呼叫其父類別構造器,但是Java會自動呼叫其父類別的構造器。即使不為Cartoon()創建構造器,編譯器也會合成一個預設的無參構造器,該構造器將呼叫基底類別的建構器。
當基類中的建構器都是帶有參數時,編譯器不會自動調用,必須用關鍵字super明確地調用基底類別建構器,並且傳入適當的參數,對應的例子程式碼如下:
//: reusing/Chess.java // Inheritance, constructors and arguments. import static net.mindview.util.Print.*; class Game { Game(int i) { print("Game constructor"); } } class BoardGame extends Game { BoardGame(int i) { super(i); print("BoardGame constructor"); } } public class Chess extends BoardGame { Chess() { super(11); print("Chess constructor"); } public static void main(String[] args) { Chess x = new Chess(); } } /* Output: Game constructor BoardGame constructor Chess constructor *///:~
從上述程式碼中可以觀察到,必須在子類別Chess建構器中顯示的使用super呼叫父類別建構器並傳入適當參數。而且,呼叫基底類別構造器必須是在子類別建構器中做的第一件事。
在此之前,我們先來探討一下物件參考的初始化問題。在Java中,類別中域為基本型別時能夠自動被初始化為零,但是物件參考會被初始化為null。我們往往需要在適當的位置對其進行初始化,下面是幾個可以進行初始化的位置:
1.在定義物件的地方。 這表示它們總是能夠在建構器被呼叫之前被初始化。
2.在類別的建構器中。
3.就在正要使用這些物件之前,這種方式稱為惰性初始化。
記住上面的第1點,下面看一個比較複雜的例子來看基類構造器的呼叫順序問題。
// reusing/Ex7/C7.java // TIJ4 Chapter Reusing, Exercise 7, page 246 /* Modify Exercise 5 so that A and B have constructors with arguments instead * of default constructors. Write a constructor for C and perform all * initialization within C's constructor. */ import static org.greggordon.tools.Print.*; class A { A(char c, int i) { println("A(char, int)");} } class B extends A { B(String s, float f){ super(' ', 0); println("B(String, float)"); } } class C7 extends A { private char c; private int i; C7(char a, int j) { super(a, j); c = a; i = j; } B b = new B("hi", 1f); // will then construct another A and then a B public static void main(String[] args) { C7 c = new C7('b', 2); // will construct an A first } }
上述這段程式碼輸出:
A(char, int)
#A(char, int)
B(String, float)
1.在new一個類別的物件時,首先調用其父類別建構器(可以是無參的和有參的,無參的系統會自動調用,有參的需要自己指定)。如上述C7中的super(a, j)
2.然後執行其成員物件初始化語句,呼叫B類別建構器,如上述的
B b = new B("hi", 1f),而B的建構器又會先呼叫基底類別A的建構器。
3.最後返回C7中的構造器,繼續執行c=a,i=j。
以上是Java基類構造器呼叫的講解(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!