關於“抽象類是否可繼承實體類”的辨析

 問:  抽象類是否可繼承實體類 (concrete class)

答: 抽象類是可以繼承實體類,但前提是實體類必須有明確的構造函數


 -------------------


答案很明確,可以繼承。其實從Object就是個實體類,java的API文檔裏,每個抽象類的條目裏都明確寫着直接或間接繼承自Object,所以這點是沒有疑問的。


關鍵在於這答案裏所說的“前提是實體類必須有明確的構造函數”一句,是什麼意思。


一般學習者會寫的簡單試驗代碼:


class A{}

abstract class B extends A{} 


結果完全正常,編譯通過。似乎和“實體類必須有明確的構造函數”完全沒有關係。


這個問題涉及到兩個個基礎知識:

1. 

所有的class都必須有一個構造方法,如果你沒有在代碼裏聲明構造方法,系統會自動給你生成一個公有無參的構造方法。而只要你自己聲明瞭一個構造方法,無論有參無參,私有公有,系統就不再幫你生成默認無參構造器了。

2.

所有的子類構造器都要求在第一行代碼中調用父類構造器,如果不寫,系統默認去調用父類的無參構造器。

 


所以,如果把系統默認配給的方法也算進去,class A{}的代碼實際上是

class A{

  public A(){}

 

B繼承 A 的時候,則是

abstract class B extends A{

  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的前綴,結果都沒有變化。個人覺得“實體類必須有明確的構造函數”一句實在是無法把這個情況表達清楚,所以廣大求職者還是寫得清楚些好。


我喜歡的寫法是“可以繼承,但是和實體類的繼承一樣,也要求父類可繼承,並且擁有子類可訪問到的構造器。” 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章