您現在的位置是:首頁 > 明星首頁明星
避免濫用繼承:程式設計師寫程式碼必須遵守的七大原則之里氏替換原則
反之則不然什麼意思
一、什麼是里氏替換原則
只要能使用父類的地方,都可以用子類替換,反之則不然。它包含如下四個方面的含義:
1、子類必須實現父類的抽象方法,但是不能覆蓋父類的非抽象方法
子類如果不實現父類的抽象方法,編譯都通不過,這點沒有問題,關鍵是不能覆蓋父類的非抽象方法。
2、子類可以增加自己特有的方法
子類如果沒有自己特有的方法,跟父類沒啥區別,這點不需要解釋。
3、當子類過載父類的方法時,方法的形參要比父類更寬鬆
如果過載的時候,引數不注意,等同於覆蓋,這點很關鍵。
4、當子類過載父類的方法時,方法的返回值要比父類更嚴格
如果不這樣,程式碼將會編譯出錯。
上面4點,關鍵的是1和3,其他的都容易理解。
二、為什麼要遵守里氏替換原則
確保合理的使用繼承
濫用繼承將會帶來嚴重後果。繼承是為了程式碼的複用,有優點也有缺點,優點是提高了程式碼的可複用性和可擴充套件性,缺點是打破了程式碼的封裝性,使子類和父類互相耦合,所以要用里氏替換原則規範繼承的使用,揚長避短。
確保使用繼承的程式碼能夠滿足開閉原則
滿足里氏替換原則的程式碼,一定也滿足開閉原則的要求。
三、如何遵守里氏替換原則
合理的抽象,確定物件關係是“Is-A”,而不是“Has-A”
例如鳥這個物件,從生物學的角度分析,鸚鵡和鴕鳥都是鳥,但是從類的繼承關係看,鸚鵡可以是鳥的子類,但是鴕鳥不能是鳥的子類,因為它不能飛。飛機能飛,但是它也不可能是鳥的子類。Is-A可以是繼承關係,而Has-A只能是組合關係。
子類繼承父類時,可以新增方法,不能覆蓋父類的方法
如果覆蓋父類的方法,可能會帶來錯誤的結果,例如有如下父類:
父類:SuperType
在構造器中呼叫了可被覆蓋的方法,有如下子類去繼承它:
子類:SubType帶覆蓋方法
執行該程式碼的時候,將會報錯,因為父類的構造器方法先於List物件例項化執行,而父類的構造器又呼叫了子類的覆蓋方法,這時候List還未被初始化,所以丟擲了空指標異常。
如果遵守里氏替換原則,將會避免這樣錯誤,同時也要注意:
父類的構造器不能呼叫可被覆蓋的方法
。
當子類過載父類的方法時,方法的形參要比父類更寬鬆,否則過載會變覆蓋
看如下程式碼,子類過載了父類的方法,但是由於過載不當,起到了覆蓋的作用,違背了里氏替換原則:
父類:SuperType
子類:SubType帶過載方法
執行方法
執行的結果是運行了子類的方法,子類並沒有覆蓋父類的方法,只是過載了父類的方法,但是由於子類過載方法的引數ArrayList比父類方法的引數List範圍上要更狹窄,所以起到了覆蓋的作用。這違反了里氏替換原則。