先介紹兩個概念
漸進式開發
繼承技術的優點之一就是它支援漸進式開發模式. 你可以引入新代碼(包括覆蓋基類代碼)而不會在現有代碼中引發bug; 事實上, 這種模式可以將新的bug隔離在新的代碼之中.
即使出現bug, 也知道它是在新代碼中, 易於差錯.
切記: 繼承代表著對一種關係的展示, 即"此新類是彼舊類的一種類型".
向上轉型
"為新類提供方法"並不是繼承技術中最重要的方面, 其最重要的方面是用來表現新類和基類之間的關係. 這種關係可以用"新類是現有類的一種類型"這句話加以概括.
由於繼承意味著基類中所有的方法在匯出類中也同樣有效, 所以能夠向基類發送的所有訊息同樣也可以嚮導出類發送.
由於向上轉型是從一個較專用類型向較通用類型轉換, 所以總是安全的. 也就是說, 匯出類是基類的一個超集. 它可能比基類含有更多的方法, 但它至少具備基類中含有的所有方法.
在向上轉型的過程中, 類介面中唯一可能發生的事情是丟失方法, 而不是擷取它們. 這就是為什麼編譯器在"未曾明確表示轉型"or"未曾指定特殊標記進行轉型"的情況下, 仍然允許向上轉型的原因.
/** *//**
* Title: Inheritance & Upcasting<br>
* Description: 此例解釋"向上轉型"概念, 無任何功能介面<br>
* Copyright: (c) 2008 Thinking in Java<br>
* Company: Augmentum Inc
* @author Forest He
* @version 1.0
*/
class Instrument ...{
public void play() ...{ System.out.println("Upcasting: 目前啟動並執行方法是基類方法play(), 基類方法tune()利用基類對象調用了play()"); }
public static void tune(Instrument i) ...{ i.play(); }
}
class Wind extends Instrument ...{
public static void main(String[] args) ...{
Wind flute = new Wind();
Instrument.tune(flute);
}
}
/**//* 上例中, tune()方法接受Instrument引用. 但在Wind.main()中, tune()方法是通過一個Wind引用而被調用的.
* 鑒於Java對類型檢查十分嚴格, 接受某種類型的方法同樣可以接受另外一種類型就會顯得很奇怪, 除非你認識到Wind對象同樣也是一種Instrument對象.
* 在tune()中, 程式碼可以對Instrument和它的所有匯出類起作用, 這種將Wind引用轉換為Instrument引用的動作, 我們稱之為"向上轉型".
*/
Choose between Composition and Inheritance
組合和繼承都允許在新類中放置子物件, 組合是顯式地這麼做, 而繼承則是隱式地做.
組合技術通常用於想在新類中使用現有類的功能而非它的介面這種情形. 但新類使用者希望看到的只是為新類所定義的介面, 而非內嵌物件的介面. 為取得此效果, 需要將新類中嵌入的現有類對象設定為private.
"is-a"(是一個)的關係是用繼承來表達的, 而"has-a"(有一個)的關係則是用組合來表達的.
在OO編程中, 產生和使用程式碼最有可能採用的方法就是直接將資料和方法封裝進一個類中, 並使用該類的對象. 也可以運用組合技術使用現有類來開發新的類; 而繼承技術實際是不太常用的.
應當慎用繼承技術, 其使用場合僅限於你確信使用該技術確實有效情況. 到底是該用Composition還是Inheritance, 一個最清晰的判斷方法就是問一問自己是否需要從新類向基類進行向上轉型. 如果需要Upcasting, 則Inheritance是必要的; 但如果不需要, 則應當好好考慮自己是否需要繼承.