一
看Think in Java,遇到個程序
class Egg2 { protected class Yolk { public Yolk() { System.out.println("Egg2.Yolk()"); } public void f() { System.out.println("Egg2.Yolk.f()"); } } private Yolk y = new Yolk(); public Egg2() { System.out.println("New Egg2()"); } public void insertYolk(Yolk yy) { y = yy; } public void g() { y.f(); } } public class BigEgg2 extends Egg2 { public class Yolk extends Egg2.Yolk { public Yolk() { System.out.println("BigEgg2.Yolk()"); } public void f() { System.out.println("BigEgg2.Yolk.f()"); } } public BigEgg2() { insertYolk(new Yolk()); } public static void main(String[] args) { // Egg2 e1 = null; // Egg2 e2 = new BigEgg2(); // new Egg2(); new BigEgg2(); // e2.g(); } } ///:~
輸出
Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
二
其實基本上我根據后面的幾個注釋,也大概明白了看的順序構造順序是什么,見圖
構造順序圖
三
但是,看了輸出,我就納悶為什么,為什么第三行不是BigEgg2.Yolk(),不能覆蓋嗎?
Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
四
分析一下
BigEgg2是Egg2的子類,他們都有Yolk的內部類,而且BigEgg2.Yolk繼承了Egg2.Yolk。注意此處,同名類可以繼承。
那么,他們構造方法為什么不能覆蓋,都是Public Yolk(){}。
當然,網上都說子類繼承父類除構造方法以外的所有方法,但這是結果,我要知道為什么!!
五
先說幾個錯誤的觀點
1.
有說構造方法的方法名與類名必須一樣,父子類不能同名,故不能繼,所以不能覆蓋構造方法。
這個不用多說,這個例子,就是大神寫出來打這樣說的人的臉的。
2.
有說因為子類繼承父類的時候,先運行父類構造函數;具體的說就是運行父類時就會先“調用”父類的構造函數,注意“調用”和繼承不是一個含義,實質上是“自動運行”。
這個強行用中文語法來解釋的,達到中文6級了啊。
3.
有說構造方法不是成員函數,故不能繼承,所以談不上覆蓋。
這個真的有道理,是java官方文檔上的。大多數人找到這里估計就滿足了。
但是,跟太陽從東方升起西方落下那樣,我想知道為甚么這么設計啊啊啊啊啊啊!!!!!
4.
正確答案
(1).構造器代表這個類本身,在創建之時申請內存。
(2).子類創建的時候,會默認在構造方法的第一行調用父類的默認構造方法-,若修改了必須顯示調用。(這就是為什么創建子類時先創建完父類的原因了)
那么很明顯了,要是同名類之間可以覆蓋了,子類創建時就是創建了兩個自己而沒有父類。
Java設計的時候,他們絕對想到有些人會像強迫症那樣折騰個同名類繼承,然后實現構造覆蓋的場景吧....