大家都知道this 和 super 調用構造函數時都必須放在第一句,今天同學問我的一個問題有點意思。
那么:我怎么在子類中 顯式的用 super 初始化父類同時用 this 初始化子類?
-------------------------------------------------------------------------------------
首先大家必須認識到兩點:
1. super 調用構造函數的 作用是 為了初始化子類前先初始化父類,僅此而已。
2. 每個類的構造函數有且僅有一個會執行屬性的初始化,即使你用的this, 那最后實際上也是this 指向的那個構造函數會執行。
下面分兩種情況具體分析下
(1) 父類提供了無參的構造函數
這種情況比較簡單,因為子類的構造函數會自動的調用父類的無參構造方法,不需要顯式的加 super()。
但如果我手賤,硬要加怎么辦?那么會無法編譯,不然這樣就多次初始化父類了,有 導致不一致狀態 的潛在風險。
如下圖:父類提供了一個無參的構造函數,子類有一個默認構造函數,三個帶參的構造函數。
上文說了,實例化時,有且僅有一個構造函數會執行,當用son1(), son1(int p3) 都最終會調用最后一個構造函數,
所以最后一個構造函數執行前會調用父類的構造函數,如果son1(), son1(int p3) 也顯示的調用super(),則多次初始化父類了,
這顯然是不對的;而 son1(int p2, int p3) 自己初始化屬性,所以沒這個問題,可以顯式的調用super()。
public class father { int age; public father(){ age = 50; } } public class son1 extends father{ int property1; int property2; int property3; public son1(){ this(1,2,3); } public son1(int p3){ this(1,2,p3); } public son1(int p2, int p3){ super(); property1 = 1; this.property2 = p2; this.property3 = p3; } public son1(int p1, int p2, int p3){ super(); property1 = p1; property2 = p2; property3 = p3; } }
(2) 父類沒有提供無參的構造函數
此時必須在子類中顯式調用super(parm) 初始化父類。
同樣,后面的兩個構造函數必須顯式的調用 super
public class Father { int age; public Father(int age) { this.age = age; } } public class Son extends Father{ int property1; int property2; int property3; //構造函數1 public Son(){ //super(40); this(1,2,3); } //構造函數2 public Son(int p3){ //super(40); this(1,2,p3); } //構造函數3 public Son(int p2, int p3){ super(40); property1 = 1; this.property2 = p2; this.property3 = p3; } //構造函數4 public Son(int p1, int p2, int p3){ super(40); property1 = p1; property2 = p2; property3 = p3; } }
總結:this 與 super 調用構造函數時,都必須第一行,這樣導致他們不能同時使用,但你並不需要擔心沒有初始化父類。
因為,this 最終指向的子類構造函數中,一定會調用super() 初始化父類,默認的或者帶參的。
