多態(tài)

1.理解java的三大特性之多態(tài)

面向?qū)ο缶幊逃腥筇匦裕悍庋b、繼承环凿、多態(tài)梧兼。

封裝隱藏了類(lèi)的內(nèi)部實(shí)現(xiàn)機(jī)制,可以在不影響使用的情況下改變類(lèi)的內(nèi)部結(jié)構(gòu)智听,同時(shí)也保護(hù)了數(shù)據(jù)羽杰。對(duì)外界而已它的內(nèi)部細(xì)節(jié)是隱藏的,暴露給外界的只是它的訪(fǎng)問(wèn)方法瞭稼。

繼承是為了重用父類(lèi)代碼忽洛。兩個(gè)類(lèi)若存在IS-A的關(guān)系就可以使用繼承。环肘,同時(shí)繼承也為實(shí)現(xiàn)多態(tài)做了鋪墊欲虚。那么什么是多態(tài)呢?多態(tài)的實(shí)現(xiàn)機(jī)制又是什么悔雹?請(qǐng)看我一一為你揭開(kāi):

所謂多態(tài)就是指程序中定義的引用變量所指向的具體類(lèi)型和通過(guò)該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定复哆,而是在程序運(yùn)行期間才確定,即一個(gè)引用變量倒底會(huì)指向哪個(gè)類(lèi)的實(shí)例對(duì)象腌零,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類(lèi)中實(shí)現(xiàn)的方法梯找,必須在由程序運(yùn)行期間才能決定。因?yàn)樵诔绦蜻\(yùn)行時(shí)才確定具體的類(lèi)益涧,這樣锈锤,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類(lèi)實(shí)現(xiàn)上,從而導(dǎo)致該引用調(diào)用的具體方法隨之改變久免,即不修改程序代碼就可以改變程序運(yùn)行時(shí)所綁定的具體代碼浅辙,讓程序可以選擇多個(gè)運(yùn)行狀態(tài),這就是多態(tài)性阎姥。

比如你是一個(gè)酒神记舆,對(duì)酒情有獨(dú)鐘。某日回家發(fā)現(xiàn)桌上有幾個(gè)杯子里面都裝了白酒呼巴,從外面看我們是不可能知道這是些什么酒泽腮,只有喝了之后才能夠猜出來(lái)是何種酒。你一喝衣赶,這是劍南春诊赊、再喝這是五糧液、再喝這是酒鬼酒….在這里我們可以描述成如下:

酒 a = 劍南春

酒 b = 五糧液

酒 c = 酒鬼酒

這里所表現(xiàn)的的就是多態(tài)屑埋。劍南春豪筝、五糧液、酒鬼酒都是酒的子類(lèi)摘能,我們只是通過(guò)酒這一個(gè)父類(lèi)就能夠引用不同的子類(lèi),這就是多態(tài)——我們只有在運(yùn)行的時(shí)候才會(huì)知道引用變量所指向的具體實(shí)例對(duì)象敲街。

誠(chéng)然团搞,要理解多態(tài)我們就必須要明白什么是“向上轉(zhuǎn)型”。在繼承中我們簡(jiǎn)單介紹了向上轉(zhuǎn)型多艇,這里就在啰嗦下:在上面的喝酒例子中逻恐,酒(Win)是父類(lèi),劍南春(JNC)峻黍、五糧液(WLY)复隆、酒鬼酒(JGJ)是子類(lèi)。我們定義如下代碼:

JNC a = new? JNC();

對(duì)于這個(gè)代碼我們非常容易理解無(wú)非就是實(shí)例化了一個(gè)劍南春的對(duì)象嘛姆涩!但是這樣呢挽拂?

Wine a = new JNC();

在這里我們這樣理解,這里定義了一個(gè)Wine 類(lèi)型的a骨饿,它指向JNC對(duì)象實(shí)例亏栈。由于JNC是繼承與Wine,所以JNC可以自動(dòng)向上轉(zhuǎn)型為Wine宏赘,所以a是可以指向JNC實(shí)例對(duì)象的绒北。這樣做存在一個(gè)非常大的好處,在繼承中我們知道子類(lèi)是父類(lèi)的擴(kuò)展察署,它可以提供比父類(lèi)更加強(qiáng)大的功能闷游,如果我們定義了一個(gè)指向子類(lèi)的父類(lèi)引用類(lèi)型,那么它除了能夠引用父類(lèi)的共性外,還可以使用子類(lèi)強(qiáng)大的功能脐往。

但是向上轉(zhuǎn)型存在一些缺憾休吠,那就是它必定會(huì)導(dǎo)致一些方法和屬性的丟失,而導(dǎo)致我們不能夠獲取它們钙勃。

具體代碼:



public class Wine {

public void fun1(){

System.out.println("Wine 的Fun.....");

fun2();

}public void fun2(){

System.out.println("Wine 的Fun2...");

}

}public class JNC extends Wine{/*** @desc 子類(lèi)重載父類(lèi)方法

*? ? ? ? 父類(lèi)中不存在該方法蛛碌,向上轉(zhuǎn)型后,父類(lèi)是不能引用該方法的


public void fun1(String a){

System.out.println("JNC 的 Fun1...");

fun2();

}/*** 子類(lèi)重寫(xiě)父類(lèi)方法

* 指向子類(lèi)的父類(lèi)引用調(diào)用fun2時(shí)辖源,必定是調(diào)用該方法*/publicvoidfun2(){

System.out.println("JNC 的Fun2...");

}

}public class? Test {

public static void main(String[] args) {

Wine a=newJNC();

a.fun1();

}

}

Output:

Wine 的Fun.....

JNC 的Fun2...



從程序的運(yùn)行結(jié)果中我們發(fā)現(xiàn)蔚携,a.fun1()首先是運(yùn)行父類(lèi)Wine中的fun1().然后再運(yùn)行子類(lèi)JNC中的fun2()。

分析:在這個(gè)程序中子類(lèi)JNC重載了父類(lèi)Wine的方法fun1()克饶,重寫(xiě)fun2()酝蜒,而且重載后的fun1(String a)與 fun1()不是同一個(gè)方法,由于父類(lèi)中沒(méi)有該方法矾湃,向上轉(zhuǎn)型后會(huì)丟失該方法亡脑,所以執(zhí)行JNC的Wine類(lèi)型引用是不能引用fun1(String a)方法。而子類(lèi)JNC重寫(xiě)了fun2() 邀跃,那么指向JNC的Wine引用會(huì)調(diào)用JNC中fun2()方法霉咨。

所以對(duì)于多態(tài)我們可以總結(jié)如下:

指向子類(lèi)的父類(lèi)引用由于向上轉(zhuǎn)型了,它只能訪(fǎng)問(wèn)父類(lèi)中擁有的方法和屬性拍屑,而對(duì)于子類(lèi)中存在而父類(lèi)中不存在的方法途戒,該引用是不能使用的,盡管是重載該方法僵驰。若子類(lèi)重寫(xiě)了父類(lèi)中的某些方法喷斋,在調(diào)用該些方法的時(shí)候,必定是使用子類(lèi)中定義的這些方法(動(dòng)態(tài)連接蒜茴、動(dòng)態(tài)調(diào)用)星爪。

對(duì)于面向?qū)ο蠖眩鄳B(tài)分為編譯時(shí)多態(tài)和運(yùn)行時(shí)多態(tài)粉私。其中編輯時(shí)多態(tài)是靜態(tài)的顽腾,主要是指方法的重載,它是根據(jù)參數(shù)列表的不同來(lái)區(qū)分不同的函數(shù)毡鉴,通過(guò)編輯之后會(huì)變成兩個(gè)不同的函數(shù)崔泵,在運(yùn)行時(shí)談不上多態(tài)。而運(yùn)行時(shí)多態(tài)是動(dòng)態(tài)的猪瞬,它是通過(guò)動(dòng)態(tài)綁定來(lái)實(shí)現(xiàn)的憎瘸,也就是我們所說(shuō)的多態(tài)性。

多態(tài)的實(shí)現(xiàn)

2.1實(shí)現(xiàn)條件

在剛剛開(kāi)始就提到了繼承在為多態(tài)的實(shí)現(xiàn)做了準(zhǔn)備陈瘦。子類(lèi)Child繼承父類(lèi)Father幌甘,我們可以編寫(xiě)一個(gè)指向子類(lèi)的父類(lèi)類(lèi)型引用,該引用既可以處理父類(lèi)Father對(duì)象,也可以處理子類(lèi)Child對(duì)象锅风,當(dāng)相同的消息發(fā)送給子類(lèi)或者父類(lèi)對(duì)象時(shí)酥诽,該對(duì)象就會(huì)根據(jù)自己所屬的引用而執(zhí)行不同的行為,這就是多態(tài)皱埠。即多態(tài)性就是相同的消息使得不同的類(lèi)做出不同的響應(yīng)肮帐。

Java實(shí)現(xiàn)多態(tài)有三個(gè)必要條件:繼承、重寫(xiě)边器、向上轉(zhuǎn)型训枢。

繼承:在多態(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í)行不同的行為际长。

對(duì)于Java而言耸采,它多態(tài)的實(shí)現(xiàn)機(jī)制遵循一個(gè)原則:當(dāng)超類(lèi)對(duì)象引用變量引用子類(lèi)對(duì)象時(shí),被引用對(duì)象的類(lèi)型而不是引用變量的類(lèi)型決定了調(diào)用誰(shuí)的成員方法工育,但是這個(gè)被調(diào)用的方法必須是在超類(lèi)中定義過(guò)的洋幻,也就是說(shuō)被子類(lèi)覆蓋的方法。

2.2實(shí)現(xiàn)形式

在Java中有兩種形式可以實(shí)現(xiàn)多態(tài)翅娶。繼承和接口。

2.2.1好唯、基于繼承實(shí)現(xiàn)的多態(tài)

基于繼承的實(shí)現(xiàn)機(jī)制主要表現(xiàn)在父類(lèi)和繼承該父類(lèi)的一個(gè)或多個(gè)子類(lèi)對(duì)某些方法的重寫(xiě)竭沫,多個(gè)子類(lèi)對(duì)同一方法的重寫(xiě)可以表現(xiàn)出不同的行為。

public class Wine {

private String name;

public String getName() {

return name;

}

public void setName(String name) {

this.name =name;

}

public Wine(){

}

public String drink(){

return "喝的是 " +getName();

}/*** 重寫(xiě)toString()*/

public String toString(){

return null;

}

}

public class JNC extends Wine{

public JNC(){

setName("JNC");

}/*** 重寫(xiě)父類(lèi)方法骑篙,實(shí)現(xiàn)多態(tài)*/

public String drink(){

return "喝的是 " + getName();

}/*** 重寫(xiě)toString()*/

public String toString(){

return "Wine : " +getName();

}

}

public class JGJ extends Wine{

public JGJ(){

setName("JGJ");

}/*** 重寫(xiě)父類(lèi)方法蜕提,實(shí)現(xiàn)多態(tài)*/

public String drink(){

return "喝的是 " +getName();

}/*** 重寫(xiě)toString()*/

public String toString(){

return "Wine : " +getName();

}

}

public class Test {

public static void main(String[] args) {

//定義父類(lèi)數(shù)組

Wine[] wines =new Wine[2];

//定義兩個(gè)子類(lèi)

JNC jnc = new JNC();

JGJ jgj = new JGJ();//父類(lèi)引用子類(lèi)對(duì)象wines[0] =jnc;

wines[1] = jgj ;

for(inti = 0 ; i < 2 ; i++){

System.out.println(wines[i].toString()+ "--" +wines[i].drink());

}

System.out.println("-------------------------------");

}

}

OUTPUT:

Wine : JNC--喝的是 JNC

Wine : JGJ--喝的是 JGJ-------------------------------

在上面的代碼中JNC、JGJ繼承Wine靶端,并且重寫(xiě)了drink()谎势、toString()方法,程序運(yùn)行結(jié)果是調(diào)用子類(lèi)中方法杨名,輸出JNC脏榆、JGJ的名稱(chēng),這就是多態(tài)的表現(xiàn)台谍。不同的對(duì)象可以執(zhí)行相同的行為须喂,但是他們都需要通過(guò)自己的實(shí)現(xiàn)方式來(lái)執(zhí)行,這就要得益于向上轉(zhuǎn)型了。

我們都知道所有的類(lèi)都繼承自超類(lèi)Object坞生,toString()方法也是Object中方法仔役,當(dāng)我們這樣寫(xiě)時(shí):

Object o =new JGJ();

System.out.println(o.toString());

輸出的結(jié)果是Wine : JGJ。

Object是己、Wine又兵、JGJ三者繼承鏈關(guān)系是:JGJ—>Wine—>Object。所以我們可以這樣說(shuō):當(dāng)子類(lèi)重寫(xiě)父類(lèi)的方法被調(diào)用時(shí)卒废,只有對(duì)象繼承鏈中的最末端的方法才會(huì)被調(diào)用沛厨。但是注意如果這樣寫(xiě):

Object o =new Wine();

System.out.println(o.toString());

輸出的結(jié)果應(yīng)該是Null,因?yàn)镴GJ并不存在于該對(duì)象繼承鏈中升熊。

所以基于繼承實(shí)現(xiàn)的多態(tài)可以總結(jié)如下:對(duì)于引用子類(lèi)的父類(lèi)類(lèi)型俄烁,在處理該引用時(shí),它適用于繼承該父類(lèi)的所有子類(lèi)级野,子類(lèi)對(duì)象的不同页屠,對(duì)方法的實(shí)現(xiàn)也就不同,執(zhí)行相同動(dòng)作產(chǎn)生的行為也就不同蓖柔。

如果父類(lèi)是抽象類(lèi)辰企,那么子類(lèi)必須要實(shí)現(xiàn)父類(lèi)中所有的抽象方法,這樣該父類(lèi)所有的子類(lèi)一定存在統(tǒng)一的對(duì)外接口况鸣,但其內(nèi)部的具體實(shí)現(xiàn)可以各異牢贸。這樣我們就可以使用頂層類(lèi)提供的統(tǒng)一接口來(lái)處理該層次的方法。

2.2.2镐捧、基于接口實(shí)現(xiàn)的多態(tài)

繼承是通過(guò)重寫(xiě)父類(lèi)的同一方法的幾個(gè)不同子類(lèi)來(lái)體現(xiàn)的潜索,那么就可就是通過(guò)實(shí)現(xiàn)接口并覆蓋接口中同一方法的幾不同的類(lèi)體現(xiàn)的。

在接口的多態(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ō)有更好的靈活性九默。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末震放,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子荤西,更是在濱河造成了極大的恐慌澜搅,老刑警劉巖伍俘,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異勉躺,居然都是意外死亡癌瘾,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)饵溅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)妨退,“玉大人,你說(shuō)我怎么就攤上這事蜕企∫Ш桑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵轻掩,是天一觀的道長(zhǎng)幸乒。 經(jīng)常有香客問(wèn)我,道長(zhǎng)唇牧,這世上最難降的妖魔是什么罕扎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮丐重,結(jié)果婚禮上腔召,老公的妹妹穿的比我還像新娘。我一直安慰自己扮惦,他們只是感情好臀蛛,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著崖蜜,像睡著了一般浊仆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上豫领,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天氧卧,我揣著相機(jī)與錄音,去河邊找鬼氏堤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛搏明,可吹牛的內(nèi)容都是我干的鼠锈。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼星著,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼购笆!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起虚循,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤同欠,失蹤者是張志新(化名)和其女友劉穎样傍,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體铺遂,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡衫哥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了襟锐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撤逢。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖粮坞,靈堂內(nèi)的尸體忽然破棺而出蚊荣,到底是詐尸還是另有隱情,我是刑警寧澤莫杈,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布互例,位于F島的核電站,受9級(jí)特大地震影響筝闹,放射性物質(zhì)發(fā)生泄漏媳叨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一丁存、第九天 我趴在偏房一處隱蔽的房頂上張望肩杈。 院中可真熱鬧,春花似錦解寝、人聲如沸扩然。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)夫偶。三九已至,卻和暖如春觉增,著一層夾襖步出監(jiān)牢的瞬間兵拢,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工逾礁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留说铃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓嘹履,卻偏偏與公主長(zhǎng)得像腻扇,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子砾嫉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • JAVA面試題 1幼苛、作用域public,private,protected,以及不寫(xiě)時(shí)的區(qū)別答:區(qū)別如下:作用域 ...
    JA尐白閱讀 1,143評(píng)論 1 0
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,679評(píng)論 0 9
  • 當(dāng)鮮活的生命降臨在這個(gè)世界上焕刮,我們什么都不懂得舶沿,一切顯得既熟悉又陌生墙杯。只有等別人告訴你,教你括荡,那是天高镐,是藍(lán)色的,那...
    指末閱讀 364評(píng)論 0 4
  • 文/金澤香 52歲的天王巨星郭富城終于松口透露有結(jié)婚計(jì)劃,對(duì)像是名不見(jiàn)經(jīng)傳的小模特召夹,生于安徽某縣城今年29歲的方媛...
    金澤香閱讀 843評(píng)論 0 3
  • “人應(yīng)該活在自己的時(shí)代 ”第一次聽(tīng)這句話(huà)應(yīng)該是黃磊在綜藝節(jié)目說(shuō)的岩喷,滿(mǎn)滿(mǎn)老干部既視感,一開(kāi)始我是不屑這句話(huà)的监憎,這分明...
    yierjie閱讀 479評(píng)論 1 2