關於「抽象類是否可繼承實體類」的辨析

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

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


 -------------------函數


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


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


通常學習者會寫的簡單試驗代碼:繼承


class A{}ip

abstract class B extends A{} 文檔


結果徹底正常,編譯經過。彷佛和「實體類必須有明確的構造函數」徹底沒有關係。it


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

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的前綴,結果都沒有變化。我的以爲「實體類必須有明確的構造函數」一句實在是沒法把這個狀況表達清楚,因此廣大求職者仍是寫得清楚些好。


我喜歡的寫法是「能夠繼承,可是和實體類的繼承同樣,也要求父類可繼承,而且擁有子類可訪問到的構造器。」