前言: 對(duì)菜鳥(niǎo)開(kāi)發(fā)者的忠告:花一萬(wàn)個(gè)小時(shí)練習(xí) Coding,不要浪費(fèi)一萬(wàn)小時(shí)無(wú)謂地 Debugging(也就說(shuō)看代碼)
                       
看上面的UML圖,我們創(chuàng)建一個(gè)抽象的Instrument類(lèi),類(lèi)中有一個(gè)抽象方法paly,然后所有的子類(lèi)都繼承這個(gè)類(lèi)并實(shí)現(xiàn)paly方法。(若不懂繼承,請(qǐng)參照另一篇:OOP之繼承那點(diǎn)事)
我們來(lái)看一下類(lèi)的實(shí)現(xiàn):

public abstract class Instrument { public abstract void Play(); } public class Guitor : Instrument { public override void Play() { Console.WriteLine(string.Format("Play {0}", this.GetType().Name)); } } public class Paino : Instrument { public override void Play() { Console.WriteLine(string.Format("Play {0}", this.GetType().Name)); } } public class Violin : Instrument { public override void Play() { Console.WriteLine(string.Format("Play {0}", this.GetType().Name)); } }
在每個(gè)子類(lèi)方法里,我們直接出去字符串。

class PRogram { static void Main(string[] args) { Guitor g = new Guitor(); g.Play(); Paino p = new Paino(); p.Play(); Violin v = new Violin(); v.Play(); Console.ReadLine(); } }
在Main方法里,我們創(chuàng)建了三個(gè)對(duì)象,然后分別輸出。 這個(gè)說(shuō)在我們還沒(méi)開(kāi)始多態(tài)之前的寫(xiě)法,好麻煩有木有(木有?蹲角落寫(xiě)100個(gè)樂(lè)器的paly).那什么是多態(tài)呢?
什么是多態(tài):一種形態(tài)的多種表現(xiàn)形式(好抽象...)
THINK IN java上寫(xiě)到:多態(tài)是消除類(lèi)型之間的耦合關(guān)系(還是很抽象)
直接看例子:

class Program { static void Main(string[] args) { PlayInstrument(new Guitor()); PlayInstrument(new Paino()); PlayInstrument(new Violin()); Console.ReadLine(); } public static void PlayInstrument(Instrument instrument) { instrument.Play(); } }
這樣的輸出是和上面的例子是一樣的,我們改變了什么,我們提供了一個(gè)方法,把3個(gè)子類(lèi)的引用放了進(jìn)去,呀,為什么PlayInstrument的形參是Instrument的對(duì)象,這就是多態(tài)的關(guān)鍵之處,
我總結(jié)了一句話:子類(lèi)的引用(new Guitor())指向父類(lèi)的對(duì)象(Instrument instrument) ;

static void Main(string[] args) { Instrument instrument = new Guitor(); instrument = new Paino(); instrument = new Violin(); Console.ReadLine(); }
這個(gè)好神奇有木有,我初學(xué)時(shí)間也覺(jué)得,這個(gè)好神奇,這個(gè)這么玩的,讓我來(lái)帶領(lǐng)大家進(jìn)入神秘的多態(tài)空間。

static void Main(string[] args) { Guitor gutior = new Guitor(); Instrument instrument = gutior; Console.ReadLine(); }
向上轉(zhuǎn)型,就說(shuō)把子類(lèi)的類(lèi)型轉(zhuǎn)成父類(lèi)的,這樣是安全的,看上面的例子,如果在VS IDE工具中查看,是沒(méi)有編譯報(bào)錯(cuò)的,這時(shí)為什么呢?我們來(lái)看張圖。
這個(gè)圓我們把他當(dāng)作堆(heap)來(lái)看,(這沒(méi)有畫(huà)棧,因?yàn)橹赶蛴懻撓蛏限D(zhuǎn)型的安全).我們來(lái)看一下Guitor里面包含了Instrument的所有的東西(除了構(gòu)造,如果說(shuō)你點(diǎn)不出來(lái)私有化的東西,你可以嘗試用反射,它的確存在) ,這樣我們把大塊變成小塊是不是很安全呢,因?yàn)槲掖髩K擁有小塊里面所有的東西,所以說(shuō)向上轉(zhuǎn)型是安全的。
注:相反來(lái)說(shuō),向下轉(zhuǎn)型是危險(xiǎn)的,因?yàn)樾K變成大塊,你不可以控制里面的東西。(協(xié)變和逆變概念也差不多,我比較喜歡叫成和諧的變->安全,逆天的變->危險(xiǎn))
這樣的話,我們把大塊轉(zhuǎn)換成小塊(Instrument instrument=new Guitor()),我們只能調(diào)用到小塊的東西了(所以我們?cè)谠O(shè)計(jì)的時(shí)候,一般會(huì)用接口去限定)
接口其實(shí)是應(yīng)該單獨(dú)拉出來(lái)談的,但是由于接口基本概念不多,只是在我們OO設(shè)計(jì)中,接口用處很大,這里屬于設(shè)計(jì)范圍,在多態(tài)中,用接口做父類(lèi)和用類(lèi)寫(xiě)法一樣的,可以去試試。
總結(jié)一下:
1.向上轉(zhuǎn)型以后,雖然引用還是原本的子類(lèi),但是只能用父類(lèi)的方法了(想想大塊變小塊)
2.父類(lèi)方法被子類(lèi)重寫(xiě)了(virtual,override)以后,向上轉(zhuǎn)型以后,調(diào)用相同的方法還是大塊的(因?yàn)樾K的被重寫(xiě)了,這樣說(shuō)感覺(jué)很牽強(qiáng),因?yàn)槿绻覀冊(cè)谧宇?lèi)中用base關(guān)鍵字還是能調(diào)用父類(lèi)的同名方法,至于這塊的內(nèi)存的調(diào)用,我一直沒(méi)找到相關(guān)資料,如果有人知道,請(qǐng)分享一下,萬(wàn)分感謝)。
3.接口和抽象類(lèi)(類(lèi))在使用多態(tài)的上面是同一個(gè)形式
感覺(jué)這邊寫(xiě)的不好...望大家補(bǔ)充和指出不足,謝謝了。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注