如果文章對你有所幫助,請點喜歡并關注,這將是我最大的動力,謝謝
繼承
-
為什么要繼承
說到OOP(面向對象)的特點,就不得不提繼承,他使代碼擁有了其他非OOP所沒有的一種獨特性---可復用性。
當你先創建了一個類之后,再創建一個新類,即使他和你之前的類有相似的功能,你還是需要重新編寫此類。然而通過繼承,你也許可以不這么做。
-
繼承確定了一種關系
在繼承關系里,被繼承的類被稱為父類,而繼承的類就被稱為子類。子類繼承了父類所有的屬性(盡管private成員被隱藏起來,并且不可訪問)和方法,不僅如此,子類還可以根據自己的獨特性,擴展屬性和方法。
-
如何判讀這種繼承關系
PS:這是在編程前就需要想好的,這里講的不是通過誰extends誰來判斷
在這里我們用“是一個”和“像是一個”的關系來判斷繼承。
例如汽車就是一個交通工具。這是一種完美的繼承關系,意味著子類和父類是完全相同的類型。
至于第二個,比如說雞像是一個鳥。顯然雞具有鳥的一些屬性和方法,例如都能飛(雖然只能飛一會會,就不要深究啦,只是打個比方),都有翅膀,不過可以肯定的是,雞也具有鳥所沒有的,比如雞可以打鳴。這里就意味著子類基于父類又擴充了一些方法和屬性,而這些方法和屬性是父類無法訪問的。
但是無論如何,都不能為了繼承而繼承,也就是說,A類不能為了繼承B類的某個方法而去繼承。(針對這種情況,應該再創建一個C類,他抽取A類和B類的共性來作為他們的父類)因此,父類里的屬性和方法,子類應該全部需要。
-
父類的編寫
在父類里,填寫的屬性和方法應該都是泛化的,他不關心具體的子類有特殊性,他只關心只要是我這個類,這個大類可以做什么。比如交通工具定義一個父類類,他不關心具體的子類車有幾個輪胎,飛機是怎么飛的,他只關心可以這個類可以移動,可以產生位移。
另外一點需要提到的是
關于父類的權限,為了封裝,一般將成員變量賦值為private,但是方法,一般修飾為public。這樣做的目的是因為,假如一個與父類不在同一個包的類,想要繼承父類,就會變得簡單,當然這只是一般情況。
-
繼承的具體實現
這是父類
這是子類
如果子類只是簡單繼承一個類而不做其他事情,那么父類的方法將會直接繼承到子類中,如a.move(a),這意味著父類和子類具有相同的屬性和方法,可以說他們的類型是完全相同的,可是這樣做,是沒有任何意義的。
-
有2種方法可以使子類和父類產生差異。
-
第一種方法非常直接和簡單
直接在子類中添加新的方法和成員變量。這意味著父類的成員變量或方法不能滿足子類的需要,因此需要添加新的來滿足子類的需求。
-
第二種方法被稱為覆蓋(overriding)
overriding所要實現的是子類并不添加父類所沒有的新方法,而是只覆蓋父類的方法。(前提是父類方法訪問權限不是private,且子類方法權限大于等于父類方法)根據java的就近原則機制,在子類中執行的是子類方法(父類被覆蓋,這時如果想調用父類,需要通過super()方法),而在父類中執行的是父類方法,這是多態的一種表現,日后再寫。
如果想要改變形參,需要把@Override去掉。不過要注意的是,改變之后就不是覆蓋,而是重載,不是Override而是overload。
-
繼承后的子類運行順序
無論如何,java永遠是先進行子類構造器中的this的調用→父類成員變量初始化→父類構造方法→子類變量初始化→子類構造方法
究其原因,是因為子類因為繼承特性,所以擁有了父類的數據,也就是成員變量,而子類在寫這些數據時,必須先知道父類的如何定義或者初始化的
在這里分兩種情況。第一種,子類構造函數中有super(),那么會根據super里的參數調用相對應的父類構造方法;第二種,子類構造器中沒有super(),則默認執行沒有參數的父類構造方法,(在子類構造器中的第一行,默認有一個隱式的super()方法)這時如果父類構造器只有有參構造器,那么會報錯。上述例子中兩種情況都有講過,所以不再細述。
-
繼承中父類的private
子類可以繼承得到,但不能直接使用,由于private只能在本類訪問,因此可以通過父類的方法進行調用,在調用時如果重名需要加super
-
繼承中的this
如果子類和父類同時擁有完全一樣的成員變量,那么在子類里通過this調用成員變量時,雖然名字相同,但根據java就近原則的機制,會優先選擇子類的成員變量,而不是父類。同樣的,如果在父類里用this調用該成員變量,調用的也將是父類的成員變量。
-
java的默認繼承機制
無論你是否給一個類設計父類,實際上,即使你沒有設計父類,他都會有一個父類,那就是Object,想一想在你創建一個類的時候,是不是有這一欄
這就java的單根繼承結構。在java里每個類都只能有一個父類,而且是必須有。而一個類可以被多個類繼承。實際上這是利大于弊的。
-
繼承后的子類與父類
子類對象可以被當做父類對象來使用
子類對象不僅可以被子類的變量管理(指向內存),還可以被父類變量管理。(多態)
-
如何阻止繼承
如果需要防止你定義的類被繼承,只需將類修飾成final即可,同樣的,如果希望某個類的某一個方法不被覆蓋,也只需修飾成final即可。
最后以一段引用做結尾
由于繼承在面向對象程序設計中如此重要,所以它經常被高度強調,于是程序員新手就會有這樣的印象:處處都應該使用繼承。這會導致設計難以使用并過分復雜。實際上,在建立新類時,應該首先考慮組合,因為它更加簡單靈活。如果采用這種方式,設計會變得更加清晰。一旦有了一些經驗之后,便能夠看出必須使用繼承的場合了。——Thinking in Java