繼承的特徵
單繼承:每個子類最多只有一個直接父類,注意是直接父類,間接父類個數不限
注意父類的概念:A-->B-->C- ->D,在這裡,ABC都是D的父類,C是D的直接父類,AB是D的間接父類
父類和子類是一般和特殊的關係;子類擴展了父類,子類別是一種特殊的父類別
Object是所有類別的直接或間接父類別;定義一個類別時,若沒有直接指定父類,則預設繼承Object類別
子類別從父類別中繼承了哪些要素
子類別不繼承父類別的建構方法,但總是要呼叫父類別的建構方法
子類別繼承了父類別的實例變數和實例方法、類別變數和類別方法,當然前提是沒有被private修飾
父類別中被private修飾的成員,不會被子類別繼承
父類別中用final修飾的方法,子類別不能重寫
方法的重寫override
子類別和父類別擁有相同的方法簽名,叫做子類重寫了父類的方法
兩同兩小一大原則:
兩同:方法名相同,形參列表相同
兩小:子類方法的回傳值跟父類的相等或更小;子類別方法拋出的異常要跟父類別拋出的相等或更小
一大:子類別方法的存取權限要跟父類別的相等或更大
static:子類別方法要跟父類別方法一致,要嘛是類別方法,要嘛是實例方法,二者不能不一致
方法重寫後,子類別物件將無法存取父類別的方法,但可以在子類別方法中呼叫父類別的方法:super.實例方法,父類別名稱.類別方法
如果父類別方法是private修飾,則子類別不能重寫該方法;如果子類別擁有一個跟父類別private方法相同簽署的方法,這也不是重寫,這是子類別新加入的方法,與父類別的無關
子類別方法可能會和父類別的方法發生重載
父類別中用final修飾的方法,子類別不能重寫
super關鍵字
在子類別中,用super關鍵字呼叫父類別的實例變數或實例方法
super和static不能同時用來修飾方法;就像this不能和static不能同時修飾方法一樣
子類別從父類繼承了一個變量,又再定義了一個變量,而且同名,此時可以用super.變量名或父類名.變量名來訪問父類的這個變量
變量的查找順序
子類方法存取了一個變量,沒有明確指定呼叫者的情況下,按以下順序查找:
當前方法中,是否有同名的局部變量
當前類別中,是否有同名的成員變量
直接父類中,是否有
逐級網上追溯,如果最終沒有找到,那麼提示編譯出錯
super調用父類構造器
子類雖然不會繼承父類的構造器,但總是會調用父類的構造器。呼叫同一個類別的建構器用this,呼叫父類別的用super
明確呼叫:super呼叫語句寫在建構方法的第一行,因為this也要寫在第一行,因此super和this不會同時出現
間接呼叫:子類別方法的第一行寫的是this,被呼叫的建構器還得呼叫父類別的建構器
隱式呼叫:無super無this,系統預設呼叫父類別的無參構造
子類繼承父類,總會一級一級的往上調用父類構造器,直到調用Object的,並且是找到頂部父類構造器後,開始往下一層一層執行
例如下面的程式碼,繼承關係:A-->B-->C-->D
public class Test{ public static void main(String[] args) { D d=new D(); } } class D extends C{ D(){ System.out.println("D类构造器"); } }class C extends B{ C(){ System.out.println("C类构造器"); } }class B extends A{ B(){ System.out.println("B类构造器"); } }class A{ A(){ System.out.println("A类构造器"); } }
輸出:
A類別建構器
B類別建構器
C類別建構器
D類別建構器
如果父類別沒有無參構造,子類別又需要呼叫父類別的無參構造,那麼不能透過編譯
多態Polymorphism
簡單的說,多態就是:在一個金字塔式的繼承體系中,創造底部子類別物件時,用頂端的父類別類型指向這些底部的子類別對象,透過相同類型的引用變數呼叫同一個方法時,會出現不同的結果
多態源自於:繼承+父類型的引用指向子類型的物件+方法的重寫
引用變數有兩個類型,一個是編譯時類型,一個是運行時類型
向上轉型:父類型引用指向子類型對象,向上轉型由系統自動完成
向上轉型的情況下:透過父類型的參考可以呼叫子類別重寫了的方法,但不能存取父類別中沒有子類別中才有的實例變量,也就是說實例變數不具有多態性
instanceof與強制型別轉換
基本型有強制型別轉換,如(double)16;引用型別也存在強制型別轉換
如存在下列繼承鏈:A-->B-->C-->D-->E -->F,B b=new D(),此時用B類型指向D對象,此時可以把b變數轉為ACD類型,但不能轉為EF類型,拋出異常ClassCastException
進行強制類型轉換之前,應先用instanceof進行判斷能不能轉,避免拋出異常
X變數instanceof Y類型:判斷X變數能不能轉為Y類型,可能出現三種情況:
true表示可以轉,意味著X變數指向的物件的類型,是Y類型或Y的子類型;
false表示不可以轉,意味著X變數的類型與Y類型存在父子繼承關係,不可能是子父關係, X變數指向的物件的類型與Y類型沒有父子或子父關係,二者都是X變數類型的子類型;
編譯不通過,表示X和Y沒有父子或子父繼承關係
繼承與組合
繼承可以實現代碼的複用,但破壞了封裝;組合也可以實現代碼的複用
設計父類遵循的原則:
盡量用private隱藏父類的內部數據,不讓子類直接訪問父類別的成員變數
不要讓子類別隨意存取、修改父類別方法。父類輔助性的工具方法,用private修飾;需要讓外部呼叫的方法,用public;不希望子類重寫的方法用final修飾;希望子類重寫而不希望外部訪問則用protected
不要在父類別構造器中呼叫可能被子類別重寫的方法,後果很嚴重
設計繼承的原則:
子類別需要增加額外的屬性,而不是屬性的改變
子類別需要增加自己獨有的功能或行為,可以增加新方法,或重寫父類別方法
不要光出於程式碼複用的目的設計繼承,而要看實際情況,父類別和子類別是否有"has-a"的關係
不想讓一個類別被繼承:
final:用final修飾該類別為最終類,不能被繼承
private:用private修飾該類別的所有建構方法,這樣子類別就無法呼叫該類別的建構器,就不能繼承了,另外應提供一個靜態方法,用來返回該類別的對象
組合也能實現代碼的複用
A類復用B類的方法
A類中創建B類的對象,並以private修飾
在A類別方法中呼叫B類別物件的方法
組合還是繼承:
繼承:子類別與父類別是"is-a"關係,具體與抽象、特殊與一般的關係
組合:新類別與舊類別是"has-a"關係,整體與局部的關係
其他:
對於子類別從父類別繼承了一個變量,又定義了一個同名變數的情況下,在創建子類別物件時,為這兩個變數都分配了內存,只是父類別變數被隱藏