第8章 多態(tài)(Polymorphism)
多態(tài):也稱作動(dòng)態(tài)綁定、后期綁定或運(yùn)行時(shí)綁定。
OOP編程的三個(gè)基本特征:數(shù)據(jù)抽象嫉戚、繼承(復(fù)用)、多態(tài)维贺。
8.1 方法調(diào)用綁定(Method-call binding)
將一個(gè)方法調(diào)用與一個(gè)方法主體關(guān)聯(lián)起來稱作綁定它掂。Connecting a mehtod call to a mehtod body is called binding.
前期綁定:在程序執(zhí)行前進(jìn)行綁定(如果有的話,由編譯器和連接程序?qū)崿F(xiàn))溯泣。
它是面向過程語言中不需要選擇就默認(rèn)的綁定方式虐秋。例如,C只有一種方法調(diào)用垃沦,那就是前期綁定客给。
When binding is performed before the program is run (by the compiler and linker, if there is one), it’s called early binding. You might not have heared the term before because it has never been an option with procedural language. C compilers have only one kind of method call, and that’s early binding.
后期綁定:就是在運(yùn)行時(shí)根據(jù)對象的類型進(jìn)行綁定。后期綁定也叫做動(dòng)態(tài)綁定或運(yùn)行時(shí)綁定肢簿。
如果一種語言想實(shí)現(xiàn)后期綁定靶剑,就必須具有某種機(jī)制蜻拨,以便在運(yùn)行時(shí)能判斷對象的類型,從而調(diào)用恰當(dāng)?shù)姆椒ㄗR簿褪钦f缎讼,編譯器一直不知道對象的類型,但是方法調(diào)用機(jī)制能找到正確的方法體坑匠,并加以調(diào)用血崭。
The solution is called late binding, which means that the binding occurs at run time, based on the type of object. Late binding is also called dynamic binding or runtime binding. When a language implements late binding, there must be some mechanism to determine the type of the object at run time and to call the appropriate method. That is, the compiler still doesn’t know the object type, but the mehtod-callmechanism finds out and calls the correct method body. The late-binding mechanism varies from language to language, but you can imagine that some sort of type information must be installd in the objects.
再談final方法(非多態(tài)):
如Chapter7所說,final方法可以防止其他人覆蓋該方法厘灼。但更重要的一點(diǎn)是:這樣做可以有效地“關(guān)閉”動(dòng)態(tài)綁定夹纫,或者說,告訴編譯器不需要對其進(jìn)行動(dòng)態(tài)綁定设凹。
Why would you declare a method final? As noted in the last chapter, it prevents anyone from overriding that method. Perhaps more important, it effectively “turns off” dynamic binding, or rather it tells the compiler that dynamic binding isn’t necessary.This allows the compiler to generate slightly more efficient code for final method calls. However, in most cases it won’t make any overall performance diffeence in your program, so it’s best to only use final as a design decision, and not as an attempt to improve performance.
8.2 域與靜態(tài)方法(非多態(tài))
域是不具有多態(tài)性的舰讹,只有普通的方法調(diào)用是多態(tài)的。
如果直接訪問某個(gè)域围来,這個(gè)訪問就將在編譯期進(jìn)行解析跺涤,即域是靜態(tài)解析的。
eg: 當(dāng)Sub對象轉(zhuǎn)型為Super引用時(shí)监透,任何域訪問操作都將由編譯器解析桶错,因此不是多態(tài)的。Super.field和Sub.field分配了不同的存儲(chǔ)空間胀蛮。這樣院刁,Sub實(shí)際上包含兩個(gè)稱為field的域:它自己的和它從Super處得到的。
靜態(tài)方法也不具有多態(tài)性的粪狼。
如前文所述退腥,靜態(tài)方法是與類,而非與單個(gè)的對象相關(guān)聯(lián)的再榄。
8.3 構(gòu)造器內(nèi)部的多態(tài)方法的行為(慎用=屏酢)
如果在構(gòu)造器內(nèi)部調(diào)用正在構(gòu)造的對象的某個(gè)動(dòng)態(tài)綁定方法,由于動(dòng)態(tài)綁定是在運(yùn)行時(shí)才決定的困鸥,而此時(shí)嗅蔬,該對象還正在構(gòu)造中,所以它不知道自己屬于哪個(gè)類(父類還是自己)疾就,并且方法所操縱的成員可能還未進(jìn)行初始化澜术,這可能會(huì)產(chǎn)生一引起難于發(fā)現(xiàn)的隱藏錯(cuò)誤。
8.3.1 構(gòu)造器編碼原則:
1. 盡可能的簡單的方法猬腰,慎用重載方法鸟废;
2. 安全調(diào)用:使用final或private方法;
8.3.2 協(xié)變返回類型(Java SE5新增):
允許@override的重寫方法姑荷,可以返回super.method()的return類型的派生類型盒延。
8.4 初始化的實(shí)際順序(由內(nèi)到外&遞歸方式執(zhí)行構(gòu)造K趵蕖)
step1: 在其他任何事物發(fā)生之前,將分配給對象的存儲(chǔ)空間初始化成二進(jìn)制的零兰英。
step2: 調(diào)用父類的構(gòu)造過程(遞歸方式:同派生類的step1&2&3&4)撇叁。
step3: 按照聲明的順序調(diào)用成員變量的初始化。
step4: 調(diào)用導(dǎo)出類(派生類)的構(gòu)造器主體畦贸。
8.5 繼承和清理的順序
8.5.1 構(gòu)造&普通方法的區(qū)別:
構(gòu)造方法:可不主動(dòng)調(diào)用super.構(gòu)造()陨闹,如顯式調(diào)用,需要放在構(gòu)造方法第一行薄坏;
普通方法:需自行主動(dòng)調(diào)用super.method()趋厉,否則不會(huì)自動(dòng)執(zhí)行!
8.5.1 構(gòu)造&清理順序的區(qū)別:
構(gòu)造初始化:先執(zhí)行super.構(gòu)造()胶坠,再執(zhí)行派生類的構(gòu)造方法君账;
清理(相反):先執(zhí)行派生類的清理方法,再執(zhí)行基類的清理方法沈善;(WHY乡数??闻牡?)
8.6 用繼承進(jìn)行設(shè)計(jì)
繼承:編譯時(shí)净赴,已確定具體類型;
組合:更靈活的編碼設(shè)計(jì)(建議優(yōu)先選擇)罩润,非寫死的代碼層次結(jié)構(gòu)玖翅;
8.6.1 純繼承&擴(kuò)展
方式1:純繼承(is-a):
特征:只@override 基類已有的方法:super.method(),不新增其他方法割以;
優(yōu)點(diǎn):向上轉(zhuǎn)型是安全的(子類不含額外信息)金度。
方式2:擴(kuò)展繼承(is-like-a):
特征:派生類 新增其他方法;
優(yōu)點(diǎn):向上轉(zhuǎn)型時(shí)會(huì)丟失子類信息(子類含額外信息)严沥。
8.6.2 向下&向上轉(zhuǎn)型和RTTI:
向上轉(zhuǎn)型(downcasting):安全的猜极,類似于基本數(shù)據(jù)類型的窄向轉(zhuǎn)換;
向下轉(zhuǎn)型(upcasting):不安全的消玄,類似于基本數(shù)據(jù)類型的寬向轉(zhuǎn)換(可能會(huì)調(diào)用到super中并不存在的方法)魔吐;
RTTI: Runtime type indentification(運(yùn)行時(shí)類型識(shí)別),Java中所有的類型轉(zhuǎn)換(casting)都會(huì)執(zhí)行莱找,異常時(shí)throws ClassCastException.