James Gosling 曾表示:「若重設計 Java,我會拋棄類(指實現繼承)」。接口繼承(implements)優於實現繼承(extends),這是《Java 設計模式》一書的核心主張。優秀設計者 80% 代碼面向接口編程,而非具體基類。
// 僵化代碼
void g(LinkedList list) { list.add(...); g2(list); }
// 需求變更:換成 HashSet,須修改 g 簽名及所有調用鏈
// 靈活代碼
void g(Collection list) { list.add(...); g2(list); }
// 僅需 new HashSet(),零修改傳播
面向接口編程將變化點隔離,支撐敏捷開發中「並行設計與編碼」的核心需求。
子類繼承父類實現細節,父類修改私有邏輯(如新增方法、調用關係變更)可能導致子類行為異常。經典案例:Stack extends Vector 導致 push/pop 與 insertElementAt 邏輯衝突,指針錯位產生「垃圾元素」。
補救措施(覆寫所有可變方法、拋出異常)將編譯期錯誤轉為運行期異常,且違背接口隔離原則。
繼承本意是封裝「可變性」(同一繼承體系下不同具體行為),而非單純代碼復用。MonitorableStack extends Stack 看似合理,但依賴父類 pushMany 調用 push 的實現細節,一旦父類優化改為批量操作,子類監聽邏輯失效。
class Stack {
private List<Object> data = new ArrayList<>();
private int pointer = 0;
public void push(Object o) { data.add(pointer++, o); }
public Object pop() { return data.remove(--pointer); }
// 無繼承,完全封裝內部數據結構
}
優勢:
removeRange)僅當滿足所有條件時:
其餘場景,**組合優於繼承** 是鐵律。