摘要:實(shí)現(xiàn)多態(tài)的三個(gè)必要條件繼承在多態(tài)中必須存在有繼承關(guān)系的子類(lèi)和父類(lèi)。參考面試題解惑系列九繼承多態(tài)重載和重寫(xiě)面向?qū)ο笕筇匦苑庋b,繼承,多態(tài)以及抽象接口的介紹
1. 面向?qū)ο缶幊痰娜筇匦?/b>版權(quán)聲明:本文由吳仙杰創(chuàng)作整理,轉(zhuǎn)載請(qǐng)注明出處:https://segmentfault.com/a/1190000009141566
Java 面向?qū)ο缶幊逃腥筇匦裕悍庋b、繼承、多態(tài)。
1.1 封裝(Encapsulation)封裝
: 隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外公開(kāi)訪(fǎng)問(wèn)方法,控制在程序中屬性的讀和寫(xiě)的訪(fǎng)問(wèn)級(jí)別。
增強(qiáng)安全性和簡(jiǎn)化編程,使用者不必了解具體的實(shí)現(xiàn)細(xì)節(jié),而只要通過(guò)對(duì)外公開(kāi)的訪(fǎng)問(wèn)方法,來(lái)使用類(lèi)的成員。
1.1.2 封裝的基本要求把所有的屬性私有化。
對(duì)每個(gè)屬性提供 getter 和 setter 方法。
如果有一個(gè)帶參的構(gòu)造函數(shù)的話(huà),那一定要寫(xiě)一個(gè)不帶參的構(gòu)造函數(shù)。
建議重寫(xiě) toString 方法,但這不是必須的。
1.2 繼承(Inheritance)繼承
: 可以理解為,在一個(gè)現(xiàn)有類(lèi)的基礎(chǔ)之上,增加新的方法或重寫(xiě)已有方法,從而產(chǎn)生一個(gè)新類(lèi)。
我們?cè)诰帉?xiě) Java 代碼時(shí),每一個(gè)類(lèi)都是在繼承。因?yàn)樵?Java 中存在一個(gè)所有類(lèi)的父類(lèi)(基類(lèi)、超類(lèi)):java.lang.Object。
1.2.1 繼承和權(quán)限子類(lèi)不能繼承父類(lèi)中訪(fǎng)問(wèn)權(quán)限為 private 的成員變量和方法,也不能繼承父類(lèi)的構(gòu)造方法。子類(lèi)可以重寫(xiě)父類(lèi)的方法,及命名與父類(lèi)同名的成員變量。
有時(shí)候我們會(huì)有這樣的需求:我們需要將某些事物盡可能地對(duì)這個(gè)世界隱藏,但是仍然允許子類(lèi)的成員來(lái)訪(fǎng)問(wèn)它們。這個(gè)時(shí)候就需要使用到 protected。
類(lèi)成員訪(fǎng)問(wèn)修飾符與訪(fǎng)問(wèn)能力之間的關(guān)系:
類(lèi)型 | private | 無(wú)修飾 | protected | public |
---|---|---|---|---|
同一類(lèi) | 可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) |
同一包中的子類(lèi) | 不可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) |
同一包中的非子類(lèi) | 不可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) |
不同包中的子類(lèi) | 不可訪(fǎng)問(wèn) | 不可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) |
不同包中的非子類(lèi) | 不可訪(fǎng)問(wèn) | 不可訪(fǎng)問(wèn) | 不可訪(fǎng)問(wèn) | 可訪(fǎng)問(wèn) |
Java 中類(lèi)可分為以下三種:
普通類(lèi):使用 class 定義且不含有抽象方法的類(lèi)。
抽象類(lèi):使用 abstract class 定義的類(lèi),它可以含有或不含有抽象方法。
接口:使用 interface 定義的類(lèi)。
上述三種類(lèi)存在以下的繼承規(guī)律:
普通類(lèi)可以繼承(extends)普通類(lèi),可以繼承(extends)抽象類(lèi),可以繼承(implements)接口。
抽象類(lèi)可以繼承(extends)普通類(lèi),可以繼承(extends)抽象類(lèi),可以繼承(implements)接口。
接口只能繼承(extends)接口。
注意:
上述的繼承規(guī)律中,每種繼承都有各自使用的關(guān)鍵字 extends 和 implements,不可混淆使用。
上述描述中,我們沒(méi)有對(duì) implements 關(guān)鍵字使用實(shí)現(xiàn)這種說(shuō)法,是因?yàn)閺母拍钌蟻?lái)講,它也是一種繼承關(guān)系,而且對(duì)于抽象類(lèi) implements 接口而言,它并不要求一定要實(shí)現(xiàn)這個(gè)接口中定義的方法。
各繼承規(guī)律中的約束:
一個(gè)普通類(lèi)或一個(gè)抽象類(lèi),要么繼承一個(gè)普通類(lèi),要么繼承一個(gè)抽象類(lèi),即所謂的單繼承。
一個(gè)普通類(lèi)或一個(gè)抽象類(lèi)或一個(gè)接口,可以繼承任意多個(gè)接口。
一個(gè)普通類(lèi)繼承一個(gè)抽象類(lèi)后,必須實(shí)現(xiàn)這個(gè)抽象類(lèi)中定義的所有抽象(abstract)方法,否則就只能被定義為抽象類(lèi)。
一個(gè)普通類(lèi)繼承一個(gè)接口后,必須實(shí)現(xiàn)這個(gè)接口中定義的所有方法,否則就只能被定義為抽象類(lèi)。
抽象類(lèi)繼承抽象類(lèi),或者實(shí)現(xiàn)接口時(shí),可以部分、全部或者完全不實(shí)現(xiàn)父類(lèi)抽象類(lèi)的抽象(abstract)方法或父類(lèi)接口中定義的方法。
1.2.3 繼承的優(yōu)點(diǎn)繼承給我們的編程帶來(lái)的好處就是對(duì)原有類(lèi)的復(fù)用(重用)。除了繼承之外,我們還可以使用組合的方式來(lái)復(fù)用類(lèi)。
所謂組合就是把原有類(lèi)定義為新類(lèi)的一個(gè)屬性,通過(guò)在新類(lèi)中調(diào)用原有類(lèi)的方法來(lái)實(shí)現(xiàn)復(fù)用。從抽象概念上來(lái)講,新定義類(lèi)所代表的事物是原有類(lèi)所代表的事物的一種,那么這時(shí)組合就是實(shí)現(xiàn)復(fù)用更好的選擇。下面這個(gè)例子就是組合方式的一個(gè)簡(jiǎn)單示例:
/** * 寶馬 */ public class BMW { private Car car = new Car(); public void driveBMW() { // 復(fù)用汽車(chē)類(lèi)的通用駕駛方法 car.drive(); // 再寫(xiě)寶馬車(chē)的特定駕駛方法 } } /** * 汽車(chē) */ class Car { public void drive() { // 開(kāi)車(chē) } }
使用繼承和組合復(fù)用原有的類(lèi),都是一種增量式的開(kāi)發(fā)模式,這種方式帶來(lái)的好處是不需要修改原有的代碼,因此不會(huì)給原有代碼帶來(lái)新的 BUG,也不用因?yàn)閷?duì)原有代碼的修改而重新進(jìn)行測(cè)試,這對(duì)我們的開(kāi)發(fā)顯然是有益的。因此,如果我們是在維護(hù)或者改造一個(gè)原有的系統(tǒng)或模塊,尤其是對(duì)它們的了解不是很透徹的時(shí)候,就可以選擇增量開(kāi)發(fā)的模式,這不僅可以大大提高我們的開(kāi)發(fā)效率,也可以規(guī)避由于對(duì)原有代碼的修改而帶來(lái)的風(fēng)險(xiǎn)。
1.3 多態(tài)(Polymorphism)多態(tài)
: 相同的事物,調(diào)用其相同的方法,參數(shù)也相同時(shí),但表現(xiàn)的行為卻不同。
以下的例子,可幫助理解:
/** * 汽車(chē)接口 */ interface Car { // 汽車(chē)名稱(chēng) String getName(); // 獲得汽車(chē)售價(jià) int getPrice(); } // 寶馬 class BMW implements Car { public String getName() { return "BMW"; } public int getPrice() { return 300000; } } // 奔馳 class BENZ implements Car { public String getName() { return "BENZ"; } public int getPrice() { return 400000; } } // 汽車(chē)出售店 public class CarShop { // 售車(chē)收入 private int money = 0; // 賣(mài)出一部車(chē) public void sellCar(Car car) { System.out.println("車(chē)型:" + car.getName() + " 單價(jià):" + car.getPrice()); // 增加賣(mài)出車(chē)售價(jià)的收入 money += car.getPrice(); } // 售車(chē)總收入 public int getMoney() { return money; } public static void main(String[] args) { CarShop carShop = new CarShop(); // 賣(mài)出一輛寶馬 carShop.sellCar(new BMW()); // 賣(mài)出一輛奔馳 carShop.sellCar(new BENZ()); System.out.println("總收入:" + carShop.getMoney()); } }
運(yùn)行結(jié)果:
車(chē)型:BMW 單價(jià):300000 車(chē)型:BENZ 單價(jià):400000 總收入:700000
繼承是多態(tài)得以實(shí)現(xiàn)的基礎(chǔ)。針對(duì)上面的示例,多態(tài)就是一種類(lèi)型(都是 Car 類(lèi)型)表現(xiàn)出多種狀態(tài)(寶馬汽車(chē)的名稱(chēng)是 BMW,售價(jià)是 300000;奔馳汽車(chē)的名稱(chēng)是 BENZ,售價(jià)是 400000)。
綁定
: 將一個(gè)方法調(diào)用同這個(gè)方法所屬的主體(也就是對(duì)象或類(lèi))關(guān)聯(lián)起來(lái),分前期綁定和后期綁定兩種。
前期綁定:在程序運(yùn)行之前進(jìn)行綁定,由編譯器和連接程序?qū)崿F(xiàn),又叫做靜態(tài)綁定。比如 static 方法和 final 方法,注意,這里也包括 private 方法,因?yàn)樗请[式 final 的。
后期綁定:在運(yùn)行時(shí)根據(jù)對(duì)象的類(lèi)型進(jìn)行綁定,由方法調(diào)用機(jī)制實(shí)現(xiàn),因此又叫做動(dòng)態(tài)綁定,或者運(yùn)行時(shí)綁定。除了前期綁定外的所有方法都屬于后期綁定。
多態(tài)就是在后期綁定這種機(jī)制上實(shí)現(xiàn)的。
多態(tài)給我們帶來(lái)的好處是消除了類(lèi)之間的耦合關(guān)系,使程序更容易擴(kuò)展。比如在上例中,新增加一種類(lèi)型汽車(chē)的銷(xiāo)售,只需要讓新定義的類(lèi)繼承 Car 類(lèi)并實(shí)現(xiàn)它的所有方法,而無(wú)需對(duì)原有代碼做任何修改,CarShop 類(lèi)的 sellCar(Car car) 方法就可以處理新的車(chē)型了。
1.3.1 實(shí)現(xiàn)多態(tài)的三個(gè)必要條件繼承:在多態(tài)中必須存在有繼承關(guān)系的子類(lèi)和父類(lèi)。
重寫(xiě):子類(lèi)對(duì)父類(lèi)中某些方法進(jìn)行重新定義,在調(diào)用這些方法時(shí)就會(huì)調(diào)用子類(lèi)的方法。
向上轉(zhuǎn)型:在多態(tài)中需要將子類(lèi)的引用賦給父類(lèi)對(duì)象,只有這樣該引用才能夠具備技能調(diào)用父類(lèi)的方法和子類(lèi)的方法。
只有滿(mǎn)足了上述三個(gè)條件,我們才能夠在同一個(gè)繼承結(jié)構(gòu)中使用統(tǒng)一的邏輯實(shí)現(xiàn)代碼處理不同的對(duì)象,從而達(dá)到執(zhí)行不同的行為。
1.3.2 多態(tài)的實(shí)現(xiàn)方式基于繼承實(shí)現(xiàn)的多態(tài)
: 主要表現(xiàn)在父類(lèi)和繼承該父類(lèi)的一個(gè)或多個(gè)子類(lèi)對(duì)某些方法的重寫(xiě),多個(gè)子類(lèi)對(duì)同一方法的重寫(xiě)可以表現(xiàn)出不同的行為。
基于接口實(shí)現(xiàn)的多態(tài)
: 在接口的多態(tài)中,指向接口的引用必須是指定這實(shí)現(xiàn)了該接口的一個(gè)類(lèi)的實(shí)例,在運(yùn)行時(shí),根據(jù)對(duì)象引用的實(shí)際類(lèi)型來(lái)執(zhí)行對(duì)應(yīng)的方法。
繼承都是單繼承,只能為一組相關(guān)的類(lèi)提供一致的服務(wù)接口。
接口是多繼承多實(shí)現(xiàn),它能夠利用一組相關(guān)或者不相關(guān)的接口進(jìn)行組合與擴(kuò)充,能夠?qū)ν馓峁┮恢碌姆?wù)接口。所以它相對(duì)于繼承來(lái)說(shuō)有更好的靈活性。
2. 重載(overloading)重寫(xiě)(overriding)重載和重寫(xiě)都是針對(duì)方法的概念,在弄清楚這兩個(gè)概念之前,我們先來(lái)了解一下什么叫方法的型構(gòu)(signature)。
型構(gòu)
: 指方法的組成結(jié)構(gòu),具體包括方法的名稱(chēng)和參數(shù),涵蓋參數(shù)的數(shù)量、類(lèi)型以及出現(xiàn)的順序,但是不包括方法的返回值類(lèi)型,訪(fǎng)問(wèn)權(quán)限修飾符,以及 abstract、static、final 等修飾符。
示例一、下面兩個(gè)是具有相同型構(gòu)的方法:
public void method(int i, String s) { // do something } public String method(int i, String s) { // do something }
注意:在同一個(gè)類(lèi)中,是不允許定義多于一個(gè)的具有相同型構(gòu)的方法。
示例二、下面兩個(gè)是具有不同型構(gòu)的方法:
public void method(int i, String s) { // do something } public void method(String s, int i) { // do something }
了解完型構(gòu)的概念后我們?cè)賮?lái)看看重載和重寫(xiě):
重寫(xiě)(overriding)
: 指在繼承情況下,子類(lèi)中定義了與其父類(lèi)中方法具有相同型構(gòu)的新方法,就稱(chēng)為子類(lèi)把父類(lèi)的方法重寫(xiě)了。這是實(shí)現(xiàn)多態(tài)必須的步驟。
重載(overloading)
: 指在同一個(gè)類(lèi)中定義了一個(gè)以上具有相同名稱(chēng),但是型構(gòu)不同的方法。
為了加深理解,我們來(lái)考慮一個(gè)有趣的問(wèn)題:構(gòu)造器可以被重載嗎?
答案當(dāng)然是可以的,我們?cè)趯?shí)際的編程中也經(jīng)常這么做。實(shí)際上構(gòu)造器也是一個(gè)方法,構(gòu)造器名就是方法名,構(gòu)造器參數(shù)就是方法參數(shù),而它的返回值就是新創(chuàng)建的類(lèi)的實(shí)例。但是構(gòu)造器卻不可以被子類(lèi)重寫(xiě),因?yàn)樽宇?lèi)無(wú)法定義與父類(lèi)具有相同型構(gòu)的構(gòu)造器。
3. 參考JAVA面試題解惑系列(九)——繼承、多態(tài)、重載和重寫(xiě)
java 面向?qū)ο笕筇匦裕ǚ庋b,繼承,多態(tài))以及抽象、接口的介紹
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/67075.html
摘要:摘要本文章關(guān)注點(diǎn)是理解面向?qū)ο蟾拍?,從抽象的角度上去理解?duì)象,重點(diǎn)包括理解對(duì)象的作用,以及理解面向?qū)ο蟮娜筇卣鞣庋b,繼承,多態(tài)。特性多態(tài)不同對(duì)象以自己的方式響應(yīng)相同的消息的能力叫做多態(tài)。 摘要:本文章關(guān)注點(diǎn)是理解面向?qū)ο蟾拍?,從抽象的角度上去理解?duì)象,重點(diǎn)包括理解對(duì)象的作用,以及理解面向?qū)ο蟮娜筇卣鳎ǚ庋b,繼承,多態(tài))。本文重點(diǎn)關(guān)注的是理解概念。 在理解面向?qū)ο笾?,首先回答幾個(gè)問(wèn)...
摘要:很多情況下,通常一個(gè)人類(lèi),即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類(lèi)是相似對(duì)象的描述,稱(chēng)為類(lèi)的定義,是該類(lèi)對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類(lèi)的實(shí)體化形成的對(duì)象。一類(lèi)的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類(lèi)的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個(gè)人類(lèi),即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類(lèi)是相似對(duì)象的描述,稱(chēng)為類(lèi)的定義,是該類(lèi)對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類(lèi)的實(shí)體化形成的對(duì)象。一類(lèi)的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類(lèi)的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個(gè)人類(lèi),即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類(lèi)是相似對(duì)象的描述,稱(chēng)為類(lèi)的定義,是該類(lèi)對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類(lèi)的實(shí)體化形成的對(duì)象。一類(lèi)的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類(lèi)的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:多態(tài)性面向?qū)ο笕筇匦苑庋b繼承多態(tài)。面向?qū)ο蠖鄳B(tài)性存在的三個(gè)必要條件繼承重寫(xiě)父類(lèi)引用指向子類(lèi)對(duì)象多態(tài)性的實(shí)現(xiàn)方式重寫(xiě)與重載靜態(tài)多態(tài)性方法重載方法重載允許類(lèi)具有多個(gè)相同名稱(chēng)的方法,但是方法參數(shù)列表不同。 多態(tài)性 面向?qū)ο螅∣OP)三大特性:封裝、繼承、多態(tài)。 多態(tài)性(polymorphism)指同一行為具有多種不同表現(xiàn)形式,在面向?qū)ο蟪绦蛟O(shè)計(jì)中表現(xiàn)為同一消息可以根據(jù)發(fā)送對(duì)象的類(lèi)型不同,做...
閱讀 2911·2021-11-22 13:54
閱讀 3546·2021-11-16 11:44
閱讀 1386·2021-09-07 10:19
閱讀 1484·2019-08-29 17:30
閱讀 3208·2019-08-29 11:33
閱讀 3556·2019-08-26 12:18
閱讀 2896·2019-08-26 11:53
閱讀 1352·2019-08-26 10:47