一道java 常見面試題,網上找到的幾乎每一個 java 面試筆試題大全或集錦裏都能找到這道題。java
題目以下:
問: 抽象類是否可繼承實體類 (concrete class)面試
答: 抽象類是能夠繼承實體類,但前提是實體類必須有明確的構造函數
答案很明確,能夠繼承。其實從Object就是個實體類,java的API文檔裏,每一個抽象類的條目裏都明確寫着直接或間接繼承自Object,因此這點是沒有疑問的。
關鍵在於這答案裏所說的「前提是實體類必須有明確的構造函數」一句,是什麼意思。
通常學習者會寫的簡單試驗代碼:
class A{}abstract class B extends A{}
結果徹底正常,編譯經過。彷佛和「實體類必須有明確的構造函數」徹底沒有關係。
這個問題涉及到兩個個基礎知識:函數
1.全部的class都必須有一個構造方法,若是你沒有在代碼裏聲明構造方法,系統會自動給你生成一個公有無參的構造方法。而只要你本身聲明瞭一個構造方法,不管有參無參,私有公有,系統就再也不幫你生成默認無參構造器了。學習
2.全部的子類構造器都要求在第一行代碼中調用父類構造器,若是不寫,系統默認去調用父類的無參構造器。
因此,若是把系統默認配給的方法也算進去,class A{}的代碼其實是spa
class A{繼承
public A(){}ip
}
B繼承 A 的時候,則是文檔
abstract class B extends A{io
public B(){編譯
super();
}
}
要試驗出這繼承規則的內部狀況,也很簡單,在最上面那個簡單試驗代碼裏,加上個私有構造器,有參無參都行。
class A{
private A(){}
}
這個時候,如基礎知識(1) 中所說,系統再也不給你默認無參構造器, B的構造器根據(2)中的規則去調用super(),卻找不到A的無參構造器,因此致使abstract class B extends A{} 編譯不能經過。(由於A中沒有任何構造器可供子類調用,其實這個時候A只可以供內部類繼承,我用的Eclipse的3.4版本會建議給B更名,可是這解決不了這個問題。)如今,你應該瞭解了資料給的那句語焉不詳的「實體類必須有明確的構造函數」的含義:1.沒寫構造器的,那是擁有默認無參公有構造函數的,子類能夠什麼都不寫,讓默認構造器去調用它。這是最初那兩行代碼的狀況。2.寫了子類可訪問的無參構造器的,也是同樣,子類裏能夠什麼都不寫,用默認機制調用。3.寫了 有參構造器卻沒寫無參構造器的,父類裏沒有子類可訪問的無參構造器,子類必須在子類構造器裏的第一句寫明,調用父類有參構造器,並把參數傳進去。4.聲明爲final的以及全部構造器都不在子類訪問權限以內的類沒法繼承其實只要是在類的繼承中,不管抽象仍是實體,都須要符合這個規則的。在這個繼承試驗中隨時刪掉或是加上abstract的前綴,結果都沒有變化。我的以爲「實體類必須有明確的構造函數」一句實在是沒法把這個狀況表達清楚,因此廣大求職者仍是寫得清楚些好。我喜歡的寫法是「能夠繼承,可是和實體類的繼承同樣,也要求父類可繼承,而且擁有子類可訪問到的構造器。」