摘要:快速了解繼承在的繼承關系里子類可以從獲取父類的所有的公共和受保護成員字段方法和內部類。阻止繼承有些情況下,我們可能不希望子類覆蓋父類的方法,這時候,用關鍵字修飾方法即可實現該目的。
和現實世界中:子女可以繼承父母的一些特征(如:基因)、財產等一樣。OOP 中也有提供類似的特性,一個類完全可以從其它類里獲得一些屬性和方法,而不需要我們自己重新定義。這種特性簡單但強大 (Simple and powerful)。
快速了解繼承在 Java 的繼承關系里:子類可以從獲取父類的所有的公共和受保護成員(字段、方法和內部類)。當然,構造方法不是成員 (members) ,所以不能被繼承。同時,在 Java 的繼承里,子類可以做如下事情:
直接使用繼承來的字段
直接使用繼承來的方法
聲明和父類同名字段,隱藏 掉父類字段
通過父類提供的公有/受保護的方法訪問父類的私有成
創建新的字段
重寫父類同方法簽名的實例方法,隱藏 掉父類方法
重寫父類同方法簽名的靜態方法,隱藏 掉父類方法
編寫父類中不存在的方法
使用 super 關鍵字,利用父類構造方法
覆蓋當子類擁有和父類(或接口)同樣方法簽名的方法,這種現象叫做覆蓋。如以下代碼:
class Father { public void doSomthing(){ // Father do something } } class Son extends Father{ @Override public void doSomething(){ // Son do something } }
覆蓋父類實例方法
覆蓋父類靜態方法
覆蓋接口默認方法 (JDK 8+)
對于實例方法的覆蓋,實際是子類擁有自己的方法。
對于靜態方法的覆蓋,要記住:靜態方法時屬于類的,在多態中,調用的始終是類的方法。接口里的靜態方法永遠不會被覆蓋。
Father father = new Son(); Father.staticMethod(); // 這里使用的是父類Father的靜態方法
對于接口方法的覆蓋,遵循以下原則:
1.實例方法的優先級大于接口方法 (JDK8+)
interface Animal{ default void saySomething(){ // Animal say something } } interface Cow extends Animal{ default void saySomething(){ // Cow say something } } class MyCow implements Cow{ @Override public void saySomething(){ // MyCow say something } Animal myCow = new MyCow(); myCow.saySomething(); // MyCow say something }
2.有共同祖先的接口,先被覆蓋的方法(繼承深度低)會被后覆蓋的方法(繼承級別高)覆蓋
interface Animal{ default void saySomething(){ // Animal say something } } interface Pig extends Animal{ default void saySomething(){ // Pig say something } } interface BigPig extends Pig{ default void saySomething(){ // BigPig say something } } class MyPig implements Pig, BigPig{ public static void main(String...args){ MyPig myPig = new MyPig(); myPig.saySomething(); // BigPig saySomething() } }
P.S. 如果出現同一繼承級別(上例中 BigPig 和 Pig 都繼承 Animal 接口)或者子類繼承的接口無相關關系,但是接口間有同方法簽名的方法,就會出現覆蓋沖突。需要用 super 關鍵字指明具體實現哪個接口的方法或者直接覆蓋。
interface Run{ default void run(){ // Run run } } interface Car{ default void run(){ // Car run } } class MyCar implements Run, Car{ @Override public void run(){ Car.super.run(); } }
同時,我們需要注意,Java 子類覆蓋父類方法,應該:
方法的訪問權限大于等于父類
方法的返回值小于等于父類
方法拋出的異常小余等于父類
如果子類定義和父類同方法簽名的方法,會有如下結果:
x | 父類的實例方法 | 父類的靜態方法 |
---|---|---|
子類的實例方法 | 覆蓋父類方法 | 編譯錯誤 |
子類的靜態方法 | 編譯錯誤 | 隱藏父類方法 |
我們已經知道,子類可以覆蓋父類的方法。如果有一個類繼承自另外一個類,我們完全可以用一個父類來引用一個子類,如:
class Person{ public void saySomething(){ // Person say something } } class Father{ @Override public void saySomething(){ // Father say something } } class Test{ pubilc static void main(String...args){ Father father = new Father(); Person person = father; // 父類引用子類對象 } }
像這種父類引用子類對象的現象,Java 里叫做多態 (Polymorphism)。在 Java 里,只有滿足如下三個條件,才能叫多態:
繼承關系
覆蓋方法
父類引用子類對象
對于多態方法的運行,編譯器會列舉所有父類和子類符合調用方法簽名(方法名+參數列表)的方法,然后以以下原則編譯、調用方法:
成員變量(編譯和運行都看左邊)
成員方法(編譯看左邊,運行看右邊)
靜態方法(編譯和運行都看左邊)
其中,調用 private, final, static 方法的過程叫靜態綁定,否則叫動態綁定。
在使用多態的過程中,最有效的判斷語句能否通過編譯的方法是:
右邊的類是否是(IS-A)左邊的類
如示例代碼里的 father(Father) IS-A Person。
阻止繼承有些情況下,我們可能不希望子類覆蓋父類的方法,這時候,用 final 關鍵字修飾方法即可實現該目的。編譯器可以對用final的方法進行內聯操作優化處理。
強制轉換在多態里,我們知道一個父類可以引用一個子類對象:
Father father = new Son();
但是,反過來就不行了:
Son son = new Father();
如果需要讓編譯器不報錯,我們就得進行強制類型轉換操作:
Son son = (Son)new Father();
不過,這么做有風險,我們一般要使用 instanceof關鍵字先判斷,能否將父類“安全”轉換成子類:
Father f = ...; if (f instanceof Son){ Son son = (Son)f; }抽象類與接口
在繼承體系里,比較常用的就是抽象類和接口。它們比較相似:
都能被繼承
都包含抽象方法
都不能被實例化
然而,它們還是有不同的,例如:
抽象類可以聲明非 final&&static 的字段,接口不行(默認 public static final )
抽象類可以有構造方法,接口不行
抽象類可以聲明非 public 方法,接口不行(默認方法是 public )
一個類只能繼承一個抽象類,可以繼承多個接口
然后,抽象類和接口有不同的使用場景:P
抽象類:
在相關類里共享代碼
規定了一系列通用的方法和屬性
需要定義非靜態、非共有的方法
接口:
定義屬性,如可比較 (Comparable)、可飛(Flyable)
定義行為,不關心具體實現
希望使用多繼承
繼承的技巧在 Java 里,我們一般按照如下規則使用繼承:
將公共操作放在超類(父類)中
不要使用受保護的域
繼承嚴格遵循 is-a 原則
不要過多得使用反射
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66789.html
摘要:上學學的完全沒印象,基礎爛的不行,最近項目主要是改,有時間就看了一下這本書補一下基礎在寫項目時,老用到繼承,但是對其了解不深,會用但是不理解概念繼承是面向對象編程技術的一塊基石,因為它允許創建分等級層次的類。 上學學的完全沒印象,Java基礎爛的不行,最近項目主要是改bug,有時間就看了一下Head First Java這本書補一下基礎 在寫項目時,老用到Java繼承,但是對其了解不深...
摘要:本人生性愚鈍,在大學期間沒能好好領略等面向對象編程的魅力。現借助一些較為權威的書籍資料,將基礎知識里比較重要的東西整理成文,命名從基礎學。如果博文不慎侵犯了您的著作權,請聯系我。 和很多大學一樣,我的學校也是從 Java 、C++ 入手,教給我們面向對象 (OOP) 的思想。本人生性愚鈍,在大學期間沒能好好領略 Java 等面向對象編程的魅力。現借助一些較為權威的書籍資料,將 Java...
摘要:你只需要相信一句話鍵盤敲爛,月薪過萬就行了,進入正文,零基礎入門知識點大綱如下其實到目前為止,的崗位需求還是非常多的,還是大多數企業后臺開發的主流編程語言,功能強大,還是很值得學習的。 ...
摘要:自制力好的人,估計在保存后會翻出來看兩眼,過幾天又忘得一干二凈了。多思考學會思考,養成多思考的習慣。以項目來驅動自己學習,整個過程將會有趣得多。后語以上就是我對自學的幾點建議,希望對你們有幫助。 微信公眾號:一個優秀的廢人如有問題或建議,請后臺留言,我會盡力解決你的問題。 showImg(https://segmentfault.com/img/remote/1460000018208...
摘要:泛型方法泛型類中可以定義靜態非靜態的泛型方法。上述泛型類會被替換成下面形式一般使用第一個限定類型替換變為原始類型,沒有限定類型,使用替換。 引言 在面向對象的世界里,我們如果需要一個容器來盛裝對象。舉個例子:一個籃子。我們可以用這個籃子裝蘋果,也可以用這個籃子裝香蕉。基于 OOP 的思想,我們不希望為蘋果和香蕉分別創建不同的籃子;同時,我們希望放進籃子里的是蘋果,拿出來的還是蘋果。于是...
閱讀 2318·2021-08-26 14:14
閱讀 2682·2019-08-29 13:07
閱讀 2087·2019-08-26 11:44
閱讀 681·2019-08-26 10:11
閱讀 2415·2019-08-23 15:43
閱讀 3083·2019-08-23 14:17
閱讀 390·2019-08-23 12:36
閱讀 2094·2019-08-22 15:20