繼承
在前面的課程中,你已經多次看到了繼承,在Java語言中,類可以從其他類派生,從而從這些類繼承字段和方法。
定義:從另一個類派生的類稱為子類(也是派生類,擴展類或子類),派生子類的類稱為超類(也是基類或父類)。
除了Object沒有超類,每個類都有一個且只有一個直接超類(單繼承),在沒有任何其他顯式超類的情況下,每個類都隱式地是Object的子類。
類可以從派生自類的類派生的類派生,依此類推,最終派生自最頂層的類,Object,這樣的類被稱為繼承鏈中所有向后延伸到Object的類的子類。
繼承的概念很簡單但很強大:當你想要創建一個新類并且已經有一個包含你想要的一些代碼的類時,你可以從現有類派生你的新類,在這樣做時,你可以重用現有類的字段和方法,而無需自己編寫(和調試)它們。
子類從其超類繼承所有成員(字段、方法和嵌套類),構造函數不是成員,因此它們不是由子類繼承的,但是可以從子類調用超類的構造函數。
Java平臺類層次結構在java.lang包中定義的Object類定義并實現所有類共有的行為 — 包括你寫的那些,在Java平臺中,許多類直接從Object派生,其他類派生自其中一些類,依此類推,形成類的層次結構。
在層次結構的頂部,Object是所有類中最通用的,層次結構底部附近的類提供更專業的行為。
繼承的一個例子下面是類和對象課程中提供的Bicycle類的可能實現的示例代碼:
public class Bicycle { // the Bicycle class has three fields public int cadence; public int gear; public int speed; // the Bicycle class has one constructor public Bicycle(int startCadence, int startSpeed, int startGear) { gear = startGear; cadence = startCadence; speed = startSpeed; } // the Bicycle class has four methods public void setCadence(int newValue) { cadence = newValue; } public void setGear(int newValue) { gear = newValue; } public void applyBrake(int decrement) { speed -= decrement; } public void speedUp(int increment) { speed += increment; } }
作為Bicycle的子類的MountainBike類的類聲明可能如下所示:
public class MountainBike extends Bicycle { // the MountainBike subclass adds one field public int seatHeight; // the MountainBike subclass has one constructor public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) { super(startCadence, startSpeed, startGear); seatHeight = startHeight; } // the MountainBike subclass adds one method public void setHeight(int newValue) { seatHeight = newValue; } }
MountainBike繼承了Bicycle的所有字段和方法,并添加了字段seatHeight和設置它的方法,除了構造函數之外,就好像你已經從頭開始編寫了一個新的MountainBike類,有四個字段和五個方法。但是,你不必完成所有工作,如果Bicycle類中的方法很復雜并且需要花費大量時間來調試,那么這將特別有價值。
你可以在子類中執行的操作無論子類所在的包是什么,子類都會繼承其父級的所有public成員和protected成員,如果子類與其父類在同一個包中,它還會繼承父類的包私有成員,你可以按原樣使用繼承的成員,替換它們,隱藏它們或用新成員補充它們:
繼承的字段可以直接使用,就像任何其他字段一樣。
你可以在子類中聲明一個與超類中的字段同名的字段,從而隱藏它(不推薦)。
你可以在子類中聲明不在超類中的新字段。
繼承的方法可以直接使用。
你可以在子類中編寫一個新實例方法,該方法與超類中的簽名具有相同的簽名,從而覆蓋它。
你可以在子類中編寫一個新的靜態方法,該方法與超類中的簽名具有相同的簽名,從而隱藏它。
你可以在子類中聲明不在超類中的新方法。
你可以編寫一個子類構造函數,它可以隱式地或使用關鍵字super來調用超類的構造函數。
本課程的以下部分將擴展這些主題。
超類中的私有成員子類不繼承其父類的private成員,但是,如果超類具有訪問其私有字段的公共或受保護方法,則子類也可以使用這些方法。
嵌套類可以訪問其封閉類的所有私有成員 — 包括字段和方法,因此,子類繼承的public或protected嵌套類可以間接訪問超類的所有私有成員。
轉換對象我們已經看到一個對象是實例化它的類的數據類型,例如,如果我們寫
public MountainBike myBike = new MountainBike();
那么myBike是MountainBike類型。
MountainBike是Bicycle和Object的后代,因此,MountainBike是一個Bicycle并且也是一個Object,它可以在需要Bicycle或Object對象的任何地方使用。
反過來不一定是對的:Bicycle可能是MountainBike,但不一定。類似地,Object可以是Bicycle或山MountainBike,但不一定如此。
轉換顯示在繼承和實現允許的對象中使用一種類型的對象代替另一種類型的對象,例如,如果我們寫
Object obj = new MountainBike();
那么obj既是Object又是MountainBike(直到obj被賦予另一個不是MountainBike的對象的時候),這稱為隱式轉換。
另一方面,如果我們寫
MountainBike myBike = obj;
我們會得到編譯時錯誤,因為編譯器不知道obj是MountainBike,但是,我們可以告訴編譯器我們承諾通過顯式轉換將MountainBike分配給obj:
MountainBike myBike = (MountainBike)obj;
此強制轉換插入運行時檢查,為obj分配MountainBike,以便編譯器可以安全地假設obj是MountainBike,如果obj在運行時不是MountainBike,則會拋出異常。
注意:你可以使用instanceof運算符對特定對象的類型進行邏輯測試,這可以避免由于轉換不當而導致的運行時錯誤,例如:
if (obj instanceof MountainBike) { MountainBike myBike = (MountainBike)obj; }
這里,instanceof運算符驗證obj是否引用了MountainBike,以便我們可以知道不會拋出運行時異常來進行轉換。
狀態、實現和類型的多重繼承類和接口之間的一個顯著區別是類可以有字段而接口不能,此外,你可以實例化一個類來創建一個對象,這是你無法使用接口進行的,如什么是對象?部分所述,對象將其狀態存儲在字段中,這些字段在類中定義。Java編程語言不允許擴展多個類的一個原因是避免了多重繼承狀態的問題,即從多個類繼承字段的能力。例如,假設你能夠定義一個擴展多個類的新類,通過實例化該類來創建對象時,該對象將繼承所有類的超類中的字段,如果來自不同超類的方法或構造函數實例化相同的字段會怎樣?哪個方法或構造函數優先?由于接口不包含字段,因此你不必擔心多重繼承狀態所導致的問題。
實現的多重繼承是從多個類繼承方法定義的能力,這種類型的多重繼承會出現問題,例如名稱沖突和歧義,當支持這種類型的多繼承的編程語言的編譯器遇到包含具有相同名稱的方法的超類時,它們有時無法確定要訪問或調用的成員或方法。此外,程序員可以通過向超類添加新方法而無意中引入名稱沖突,默認方法引入了一種實現的多重繼承形式,一個類可以實現多個接口,該接口可以包含具有相同名稱的默認方法,Java編譯器提供了一些規則來確定特定類使用哪種默認方法。
Java編程語言支持多種類型的繼承,這是類實現多個接口的能力,對象可以有多種類型:它自己的類的類型以及該類實現的所有接口的類型。這意味著如果將變量聲明為接口的類型,則其值可以引用從實現接口的任何類實例化的任何對象,這在將接口用作類型一節中討論。
與多實現繼承一樣,一個類可以繼承它擴展的接口中定義的方法的不同實現(作為默認或靜態),在這種情況下,編譯器或用戶必須決定使用哪一個。
隱藏字段在類中,與超類中的字段具有相同名稱的字段會隱藏超類的字段,即使它們的類型不同,在子類中,超類中的字段不能通過其簡單名稱引用,相反,必須通過super訪問該字段,一般來說,我們不建議隱藏字段,因為它使代碼難以閱讀。
編寫Final類和方法你可以聲明一些或所有類的方法為final,你在方法聲明中使用final關鍵字來指示子類不能重寫該方法,Object類這樣做 — 它的一些方法是final。
如果方法具有不應被更改的實現,并且對于對象的一致狀態至關重要,則可能希望將方法設為final,例如,你可能希望在此ChessAlgorithm類中生成getFirstPlayer方法:
class ChessAlgorithm { enum ChessPlayer { WHITE, BLACK } ... final ChessPlayer getFirstPlayer() { return ChessPlayer.WHITE; } ... }
從構造函數調用的方法通常應該聲明為final,如果構造函數調用非final方法,子類可能會重新定義該方法,并產生意外或不希望看到的結果。
請注意,你還可以聲明整個類final,聲明為final的類不能被子類化,這特別有用,例如,在創建String類這樣的不可變類時。
繼承總結除了Object類之外,一個類只有一個直接超類,類繼承其所有超類中的字段和方法,無論是直接還是間接,子類可以重寫它繼承的方法,也可以隱藏它繼承的字段或方法(請注意,隱藏字段通常是糟糕的編程習慣)。
“覆蓋和隱藏方法”部分中的表顯示了使用與超類中的方法相同的簽名聲明方法的效果。
Object類是類層次結構的頂部,所有類都是此類的后代,并從中繼承方法,從Object繼承的有用方法包括toString()、equals()、clone()和getClass()。
你可以通過在類的聲明中使用final關鍵字來阻止類被子類化,同樣,你可以通過將方法聲明為final方法來防止子類重寫該方法。
抽象類只能被子類化,它無法實例化,抽象類可以包含抽象方法 — 聲明但未實現的方法,然后,子類提供抽象方法的實現。
上一篇:默認方法 下一篇:重寫和隱藏方法文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72884.html
Java? 教程 Java教程是為JDK 8編寫的,本頁面中描述的示例和實踐沒有利用在后續版本中引入的改進。 Java教程是希望使用Java編程語言創建應用程序的程序員的實用指南,其中包括數百個完整的工作示例和數十個課程,相關課程組被組織成教程。 覆蓋基礎知識的路徑 這些教程以書籍的形式提供,如Java教程,第六版,前往Amazon.com購買。 入門 介紹Java技術和安裝Java開發軟件并使用...
摘要:所以看出和兩個的對應指針數一樣,一個為一個為這就引出了變量的知識點,如手工畫的圖二為啥強制子類父類變量名不同阿里巴巴手冊是這樣寫的強制避免在子父類的成員變量之間或者不同代碼塊的局部變量之間采用完全相同的命名方式,那會導致代碼可讀性降低。 摘要: 原創出處 https://www.bysocket.com 「公眾號:泥瓦匠BYSocket 」歡迎關注和轉載,保留摘要,謝謝! 目錄 父子...
泛型、繼承和子類型 如你所知,只要類型兼容,就可以將一種類型的對象分配給另一種類型的對象,例如,你可以將Integer分配給Object,因為Object是Integer的超類型之一: Object someObject = new Object(); Integer someInteger = new Integer(10); someObject = someInteger; // OK ...
摘要:自制力好的人,估計在保存后會翻出來看兩眼,過幾天又忘得一干二凈了。多思考學會思考,養成多思考的習慣。以項目來驅動自己學習,整個過程將會有趣得多。后語以上就是我對自學的幾點建議,希望對你們有幫助。 微信公眾號:一個優秀的廢人如有問題或建議,請后臺留言,我會盡力解決你的問題。 showImg(https://segmentfault.com/img/remote/1460000018208...
定義接口 接口聲明由修飾符、關鍵字interface、接口名稱、逗號分隔的父接口列表(如果有)和接口體組成,例如: public interface GroupedInterface extends Interface1, Interface2, Interface3 { // constant declarations // base of natural logar...
閱讀 1181·2021-11-23 10:10
閱讀 1517·2021-09-30 09:47
閱讀 898·2021-09-27 14:02
閱讀 2972·2019-08-30 15:45
閱讀 3023·2019-08-30 14:11
閱讀 3616·2019-08-29 14:05
閱讀 1824·2019-08-29 13:51
閱讀 2209·2019-08-29 11:33