什麼是多態性?
多態分兩種:
(1) 編譯時多態(設計時多態):方法重載。
(2) 運行時多態:JAVA運行時系統根據呼叫此方法的實例的類型來決定選擇呼叫哪個方法則稱為運行時多態。 (我們平常說得多的事運行時多態,所以多態主要也是指運行時多態)
運行時多態存在的三個必要條件:
一、要有繼承(包括介面的實作);
二、要有重寫;
三、父類別引用指向子類別物件。
------------------------------------------------ --------------------------------
詳細解釋:
運行時多態的解釋:a.運行時多態是指程式中定義的引用變數所指向的具體類型和b.透過該引用變數發出的方法呼叫在程式設計時並不確定,而是在程式執行期間才確定,即一個引用變數倒底會指向哪個類別的實例對象,該引用變數發出的方法呼叫到底是哪個類別中實現的方法,必須在由程式運行期間才能決定.
1.程式序中定義的引用變數所指向的具體類型不確定(即一個引用變數倒底會指向哪個類別的實例物件) 。
範例:
driver 類別中drive 方法(Vehicle類別vehicle){}
•oneDriver.drive( new car() )
•oneDriver.drive( new bus() )
vehihi.子類別實例。
1.透過此引用變數發出的方法呼叫在程式設計時並不確定(該引用變數所發出的方法呼叫到底是哪個類別中實現的方法) 。
範例: 廚師,園丁,理髮師的Cut 方法呼叫.persion.cut().
--------------------------- -------------------------------------------------- ---
多態的好處:
1.可替換性(substitutability)。多態對已存在代碼具有可替換性。例如,多態對圓Circle類工作,對其他任何圓形幾何體,如圓環,也同樣工作。
2.可擴充性(extensibility)。多態對程式碼具有可擴充性。增加新的子類別不會影響已存在類別的多態性、繼承性,以及其他特性的運作和操作。實際上新加子類別更容易獲得多型功能。例如,在實現了圓錐、半圓錐以及半球體的多態基礎上,很容易增添球體類的多態性。
3.介面性(interface-ability)。多態是超類別透過方法簽名,向子類別提供了一個共同接口,由子類別來完善或覆蓋它而實現的。如圖8.3 所示。圖中超類別Shape規定了兩個實作多型態的介面方法,computeArea()以及computeVolume()。子類,如Circle和Sphere為了實現多態,完善或覆寫這兩個介面方法。
4.靈活性(flexibility)。它在應用中體現了靈活多樣的操作,並提高了使用效率。
5.簡化性(simplicity)。多態簡化對應用軟體的程式碼編寫和修改過程,尤其在處理大量物件的運算和操作時,這個特點尤其突出和重要。
實際運用:
結合設定檔的使用,聯絡Spring框架,利用反射,動態的呼叫類,同時不用修改原始程式碼,直接新增類別和修改設定文件,不需要重新啟動伺服器來擴充程式。
------------------------------------------------ --------------------------------
小結:
使用父類別類型的引用指向子類別的對象,在該引用呼叫的師父類別中定義的方法和變量,變數不能被重寫(覆蓋);如果子類別中重寫了父類別中的一個方法,那麼在呼叫這個方法的時候,將會呼叫子類別中的這個方法;
注意特殊情況,如果該父類別引用所呼叫的方法參數清單未定義,就呼叫該父類別的父類別中查找,如果還沒找到就強制向上型別轉換參數清單中的參數型別,具體優先權高到低依序如下:
this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
------------------------------------------------ --------------------------------
經典筆試題(混合重載與重寫):
(一)相關類
class A { public String show(D obj)...{ return ("A and D"); } public String show(A obj)...{ return ("A and A"); } } class B extends A{ public String show(B obj)...{ return ("B and B"); } public String show(A obj)...{ return ("B and A"); } } class C extends B...{} class D extends B...{}
(二)問題:以下輸出結果為何?
A a1 = new A();
A a2 = new B();
B2 = new B();
D d = new D();
System.out.println(a1.show(b)); ①
System.out.println(a1.show(c)); ②
System.out.println(a1.show(d)); ③
System.out.println(a2.show(b)); ④
System.out.println(a2.show(c)); ⑤
System.out.println(a2.show(d)); ⑥
System.out.println(b.show(b)); ⑦
System.out.println(b.show(c)); ⑧
System.out.println(b.show(d)); ⑨
(三)答案
① A 和 A
② A 和 A
③ A 和 D
④ B 和 A
⑤ B 和 A
⑥ A 和 D
⑦ B 和 B
⑧ B 和 B
⑨ A和D
(四)分析
①②③比較好理解,一般不會出錯。④⑤就有點糊塗了,為什麼來輸出的不是「BB」呢?運行時多態性是物件導向程式設計程式碼重用的一個最底層的機制,動態性的概念也可以被說成「一個接口,多個方法」。 ,它是一種在運行時而不是在編譯期調用重載方法的機制。的多態性的一種表現,重載重載是一類中多態性的一種表現。重寫(Overriding)。的方法,它們或有不同的參數個數或有不同的參數類型,則稱為方法的重載(Overloading)。超類別物件引用時變數引用子類別物件時,被引用物件的類型而不是引用變數的類型決定呼叫了誰的方法成員,但是這個被呼叫的方法必須是在超類別中定義過的,然後被子類別覆蓋的方法(但是如果強制把超類別轉換成子類別的話,就可以呼叫子類別中新加入而超類別沒有的方法了。)
好了,先溫習到這裡,言歸正傳!方法呼叫的優先權問題,優先權由高到低依序為:this.show(O)、super.show(O)、this.show((super)O)、super.show((super) O)。讓我們來看看它是怎麼運作的。裡面找show( B obj)方法,沒有找到,於是到A的super(超類別)找,而A沒有超類,所以轉到優先權this.show((super)O),第一個三仍然是a2,這裡O為B,(super)O即(super)B即A,它到類別A裡面找show(A obj)的方法,類別A有這個方法因此,但是由於a2引用的是類別B的一個對象,B覆寫了A的show(A obj)方法,因此最後鎖定到類別B的show(A obj),輸出為「B和A」。
再例如⑧,b.show(c),b是一個引用變量,類型為B,則this為b,c是C的一個實例,於是它到類B找show(C obj)方法,沒有找到,轉而到B的超類A裡面找,A裡面也沒有,因此也轉到第三優先權this.show((super)O),this為b,O為C,(super)O即(super) C即B,因此它到B裡面找show(B obj)方法,找到了,由於b引用的是類B的一個對象,因此直接鎖定到類B的show(B obj),輸出為"B and B 」。
依照上面的方法,可以正確地得到其他的結果。
問題還要繼續,現在我們再來看上面的分析過程是怎麼體現出藍色字體那句話的內涵的。它說:當超類別物件引用變數引用子類別物件時,被引用物件的類型而不是引用變數的類型決定了呼叫誰的成員方法,但是這個被呼叫的方法必須是在超類別中定義過的,也就是說被子類別覆蓋的方法。還是拿a2.show(b)來說吧。
a2是引用變量,類型為A,它所引用的是B的一個對象,因此這句話的意思是由B來決定調用的是哪個方法。因此應該調用B的show(B obj)從而輸出"B and B”才對。但是為什麼跟前面的分析得到的結果不相符呢? !問題在於我們不要忽略了藍色字體的後半部分,那裡特別指明:這個被呼叫的方法必須是在超類別中定義過的,也就是被子類別覆蓋的方法。 B裡面的show(B obj)在超類別A中有定義嗎?沒有!那就更談不上被覆蓋了。實際上這句話隱藏了一條訊息:它仍然是按照方法呼叫的優先權來決定的。它在類別A中找到了show(A obj),如果子類別B沒有覆寫show(A obj)方法,那麼它就呼叫A的show(A obj)(由於B繼承A,雖然沒有覆寫這個方法,但從超類別A繼承了這個方法,從某種意義上說,還是由B決定呼叫的方法,只是方法是在A中實作而已);現在子類別B覆蓋了show(A obj),因此它最終鎖定到B的show(A obj)。這就是那句話的意義。
更多JAVA 多態 由淺及深介紹相關文章請關注PHP中文網!