多態(tài)
在面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言中,多態(tài)是繼數(shù)據(jù)抽象和繼承之后的第三種基本特征。(也叫動(dòng)態(tài)綁定,后期綁定或運(yùn)行時(shí)綁定)
多態(tài)通過(guò)分離做什么和怎么做,從另一角度將接口和實(shí)現(xiàn)分離開來(lái)。多態(tài)不但能夠改善代碼的組織結(jié)構(gòu)和可讀性,還能夠創(chuàng)建可擴(kuò)展的程序--滿足項(xiàng)目初建或后續(xù)擴(kuò)展。
“封裝”通過(guò)合并特征和行為來(lái)創(chuàng)建新的數(shù)據(jù)類型。“實(shí)現(xiàn)隱藏”通過(guò)將細(xì)節(jié)私有化把接口和實(shí)現(xiàn)分離開來(lái)。多態(tài)的作用是消除類型之間的耦合關(guān)系。
一、再論向上轉(zhuǎn)型
對(duì)象既可以作為它自己本身的類型使用,也可以作為它的基類型使用。這種把對(duì)某個(gè)對(duì)象的引用視為對(duì)其基類型的引用的做法被稱為向上轉(zhuǎn)型。
多態(tài)允許我們不管導(dǎo)出類的存在,編寫代碼只是與基類打交道。
二、轉(zhuǎn)機(jī)
方法調(diào)用綁定:將一個(gè)方法調(diào)用同一個(gè)方法主體關(guān)聯(lián)起來(lái)被稱作綁定。C只能前期綁定,后期綁定就是在運(yùn)行時(shí)根據(jù)對(duì)象的類型進(jìn)行綁定。
如果一種語(yǔ)言實(shí)現(xiàn)后期綁定,就必須具有某種機(jī)制,以便在運(yùn)行時(shí)能判斷對(duì)象的類型,從而調(diào)用恰當(dāng)?shù)姆椒āR簿褪钦f(shuō)編譯器一直不知道對(duì)象的類型,但是方法調(diào)用機(jī)制能找到正確的方法體,并加以調(diào)用。
java中除了static方法和final方法(private方法屬于final方法)外,其它所有的方法都是后期綁定。這意味著通常情況下,我們不必判定是否應(yīng)該進(jìn)行后期綁定--它會(huì)自動(dòng)發(fā)生。
多態(tài)就是一項(xiàng)“將改變的事務(wù)與未變的事物分離開來(lái)”的重要技術(shù),我們所做的代碼修改,不會(huì)對(duì)程序中其他不應(yīng)受到影響的部分產(chǎn)生破壞。
向上轉(zhuǎn)型,父類調(diào)用子類方法。
三、構(gòu)造器和多態(tài)
通常構(gòu)造器不同于其他種類的方法。涉及到多態(tài)仍是如此。盡管構(gòu)造器并不具有多態(tài)性(實(shí)際上是static方法,不過(guò)該static聲明是隱式的),但還是非常有必要理解構(gòu)造器怎樣通過(guò)多態(tài)在復(fù)雜的層次結(jié)構(gòu)中運(yùn)行。
構(gòu)造器具有一項(xiàng)特殊任務(wù):檢查對(duì)象是否被正確的構(gòu)造。導(dǎo)出類只能訪問(wèn)它自己的成員,不能訪問(wèn)基類中的成員。只有基類的構(gòu)造器才具有恰當(dāng)?shù)闹R(shí)和權(quán)限來(lái)對(duì)自己的元素進(jìn)行初始化。因此,必須令所有構(gòu)造器都得到調(diào)用,否則就不可能正確構(gòu)造完整對(duì)象。這正是編譯器為什么要強(qiáng)制每個(gè)導(dǎo)出類部分都必須調(diào)用構(gòu)造器的原因。在導(dǎo)出類的構(gòu)造器主體中,如果沒(méi)有明確指定調(diào)用某個(gè)基類構(gòu)造器,它就會(huì)調(diào)用默認(rèn)構(gòu)造器。如果不存在默認(rèn)構(gòu)造器,編譯器就會(huì)報(bào)錯(cuò)(若某個(gè)類沒(méi)有構(gòu)造器,編譯器會(huì)自動(dòng)合成出一個(gè)默認(rèn)構(gòu)造器)。
組合,繼承及多態(tài)構(gòu)建構(gòu)造器的順序:1,調(diào)用基類構(gòu)造器。2,按聲明順序調(diào)用成員初始化方法。3,調(diào)用導(dǎo)出類構(gòu)造器主體。
層次結(jié)構(gòu)中的每個(gè)類對(duì)象銷毀順序和初始化的順序相反,對(duì)于字段則意味著與聲明的順序相反。執(zhí)行清理工作的時(shí)候,必須小心和謹(jǐn)慎。
構(gòu)造器的工作實(shí)際上是創(chuàng)建對(duì)象。在任何構(gòu)造器內(nèi)部,整個(gè)對(duì)象可能只是部分形成--我們只知道基類對(duì)象已經(jīng)進(jìn)行初始化。
初始化的實(shí)際過(guò)程是:1,在其他任何事物發(fā)生之前,將分配給對(duì)象的存儲(chǔ)空間初始化成二進(jìn)制的零。2,調(diào)用構(gòu)造器。3,按聲明順序調(diào)用成員初始化方法。4,調(diào)用導(dǎo)出類的構(gòu)造器主體。
編寫構(gòu)造器有一條有效的準(zhǔn)則:用盡可能簡(jiǎn)單的方法使對(duì)象進(jìn)入正常狀態(tài),如果可以的話,避免調(diào)用其他方法。
四、協(xié)變返回類型
協(xié)變返回類型:表示在導(dǎo)出類中的被覆蓋方法可以返回基類方法的返回類型的某種導(dǎo)出類型。簡(jiǎn)單來(lái)說(shuō),就是父類調(diào)用子類方法,返回另外一個(gè)類對(duì)象。
五、用繼承進(jìn)行設(shè)計(jì)
一條通用的準(zhǔn)則:用繼承表達(dá)行為間的差異,并用字段表達(dá)狀態(tài)上的變化。
純繼承與擴(kuò)展:采取純粹的方式來(lái)創(chuàng)建繼承層次結(jié)構(gòu)似乎是最好的方式。也就是說(shuō),只有在基類中已經(jīng)建立的方法才可以在導(dǎo)出類中被覆蓋。被稱作“is-a”關(guān)系,即父子類的接口完全一致,可以認(rèn)為是純替代。 “is-like-a”關(guān)系,子類含有比父類多的擴(kuò)展接口。
向上轉(zhuǎn)型(在基層層次中向上移動(dòng))會(huì)丟失具體的類型信息,安全的,向下轉(zhuǎn)型,在繼承層次中向下移動(dòng),極其不安全的。
在java語(yǔ)言中,所有轉(zhuǎn)型都會(huì)得到檢查,所以即使我們只是進(jìn)行一次普通的加括弧形式的轉(zhuǎn)換,在進(jìn)入運(yùn)行期時(shí)仍然會(huì)對(duì)其進(jìn)行檢查,以便保證它的確是我們希望的那種類型。
六、總結(jié)
多態(tài)意味著“不同的形式”。在面向?qū)ο蟮倪^(guò)程中,我們持有從基類繼承而來(lái)的相同接口,以及使用該接口的不同形式:不同版本的動(dòng)態(tài)綁定。
為了在自己的程序中有效運(yùn)用多態(tài)及面向?qū)ο蟮募夹g(shù),必須擴(kuò)展自己的編程視野,使其不僅包括個(gè)別類的成員和消息,而且還要包括類與類之間的共同特性以及它們之間的關(guān)系。盡管這需要極大的努力,但這樣做是非常值得的,因?yàn)樗梢詭?lái)很多成效:更快的程序開發(fā)過(guò)程、更好的代碼組織、更好擴(kuò)展的程序以及更容易的代碼維護(hù)等。