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