天天看點

關于Java中繼承和接口的了解關于Java中繼承和接口的了解

關于Java中繼承和接口的了解

Java語言中,為了實作代碼重用,設計了繼承這一機制,但是,其設計成單繼承,這樣設計是有原因的,如下圖:

關于Java中繼承和接口的了解關于Java中繼承和接口的了解

Figure1:deadly diamond of death

此圖問題稱為菱形問題(diamond problem),就是說,當A的子類B和C同時實作了A中的方法,則同時繼承了B和C的子類D在調用該方法時會出現混亂,無法得知該調用哪一個方法。

既然不能實作多繼承,我們就會考慮把很多方法就寫在父類裡,或者繼承抽象類,實作其方法,但是,這樣會導緻一個問題,比如說,子類不應該具有父類的某些方法,那麼,我麼為了解決這個問題,還必須在子類中重寫該方法(但是隻能在該方法中什麼也不幹),這樣的設計是很不好的。

那麼接口就來了,它解決了Java的多繼承問題,可以這樣了解,接口就是純粹的抽象類(其中的方法都是public且是抽象的),我們也可以認為接口是“另一種形式的繼承(接口繼承)”,我們可以這樣思考面向對象程式設計,其本質就是面向契約(contract)程式設計或者說是面向協定(protocol)程式設計,就像繼承,子類和父類約定好規則,子類然後去實作或者繼承,接口剛好滿足了這一點,同時它保證了隻要實作了該接口的類,其傳回的屬性都是一緻的,這樣就保證了其一緻性。同時,它避免了單繼承的不足,父類中沒有提供子類需要的方法(一般來說,父類提供公共的一些方法),不同的子類可以通過實作不同的接口來實作自己獨特的方法,這樣也保證了子類的差異性。

在繼承時,我們要注意裡氏代換原則(Liskov Substitution Principle, LSP):

Subtypes must be substitutable for their base types

也就是說子類必須能夠替換成它們的基類,更通熟一點的,在一個軟體系統中,子類應該可以替換任何基類能夠出現的地方,并且經過替換以後,代碼還能正常工作。

面向對象的設計關注的是對象的行為,它是使用“行為”來對對象進行分類的,隻有行為一緻的對象才能抽象出一個類來。我經常說類的繼承關系就是一種“Is-A”關系,實際上指的是行為上的“Is-A”關系,可以把它描述為“Act-As”。

裡氏代換原則告訴我們類的繼承原則:如果一個繼承類的對象可能會在基類出現的地方出現運作錯誤,則該子類不應該從該基類繼承,或者說,應該重新設計它們之間的關系。