本文先從繼承、覆寫、重載、多型等基本概念談起,然後說明什麼是 VMI,最後再說明有哪些 Design Patterns 使用了 VMI。
一、繼承(Inheritance)
- 這是物件導向語言的基本特性與威力強大之處。類別之間如果有繼承關係,只需在父類別定義好 欄位(屬性)與 方法(行為),繼承該父類別的子類別就擁有同樣的欄位與方法。
- 此特性可大幅減少重複程式碼。但若使用不當,繼承亦會造成擴充困難與維護不易的問題。
- 繼承同一父類別之各項子類別,在部分欄位或方法難免有些許差異,透過這兩項技巧,既可保有繼承的優點,亦能增加子類別的擴充彈性。
- 覆寫與重載 (Overloading) 不同,覆寫是改變方法的內容,而重載是改變方法的回傳值與參數。但兩者均不會改變方法的名稱。(「方法名稱 + 參數」即所謂的「Signature」)
鳥類(Bird):
public class Bird { String name; public Bird() { this.name = "Bird"; } public void eat() { System.out.println(this.name + " can eat."); } public void fly() { System.out.println(this.name + " can fly."); } }烏鴉(Crow):
public class Crow extends Bird { public Crow() { this.name = "Crow"; } }鴕鳥(Ostrich):
public class Ostrich extends Bird { public Ostrich() { this.name = "Ostrich"; } Public void fly() { system.Out.Println(this.Name + " can't fly."); } }類別圖如下:
- 繼承(Inheritance): 鳥類(Bird)是烏鴉(Crow)和鴕鳥(Ostrich)的父類別,是「繼承」的關係。
- 覆寫(Overriding):但因為鴕鳥不會飛,所以我們「覆寫」其 fly() 的行為。
三、多型(Polymorphism)
對不同型別的物件提供單一介面。多型提供一些適用於多種型別的操作。多型又可細分為三種:
有了多型,我們就可以使用同一個父類別參考來走訪所有子類別物件的實例欄位(instance field)。
四、Virtual Method Invocation
如果 Java 不支援 VMI,則在編譯時期便會將 myOstrich.fly() 連結到 Bird 類別的 fly()方法,這是靜態分派。
有了 VMI,我們也可以這樣執行所有鳥類物件的 fly() 或 eat() 方法:
五、VMI 與 Design Patterns
在 GoF 的《Design Patterns》一書中共提到 23 種設計模式,有 18 種模式都使用了 VMI。所以 VMI 是瞭解 Design Patterns 的重要關鍵!
s
對不同型別的物件提供單一介面。多型提供一些適用於多種型別的操作。多型又可細分為三種:
- Ad hoc:又稱為「重載」,有 function overloading 或 operator overloading 兩種。
- Parametric:又稱為「泛型」(generics 或 generic programming)。
- Subtyping:即「子類別多型」,一個父類別參考可以指向不同子類別的物件。
未使用多型 | 使用多型 | |
---|---|---|
Crow myCrow = new Crow(); Ostrich myOstrich = new Ostrich(); |
Bird myCrow = new Crow(); Bird myOstrich = new Ostrich(); | |
|
|
有了多型,我們就可以使用同一個父類別參考來走訪所有子類別物件的實例欄位(instance field)。
Bird myBird = new Crow(); System.out.println(myBird.name); myBird = new Ostrich(); System.out.println(myBird.name); |
Crow Ostrich |
- Virtual Method 又稱「Virtual Function」,當從父類別中繼承的時候,虛擬函式和被繼承的函式具有相同的簽名。但是在執行時期,執行系統將根據物件的型別,自動地選擇適當的具體實作執行。VMI 也適用於介面與實作。
- 虛擬函式是 OOP 實作多型的基本手段,更在 Design Patterns 之中扮演相當重要的角色。
- 在 Java 語言中,所有的方法預設都是虛擬函式。只有以關鍵字 final 標記的方法才是非虛擬函式。
- C++, Java 和 C# 都支援 VMI。
Bird myOstrich = new Ostrich(); myOstrich.fly(); | Ostrich can’t fly. |
Bird myOstrich = new Ostrich(); myOstrich.fly(); | Bird can fly. |
List |
其執行結果為: |
Bird can fly. Ostrich can't fly. Crow can fly. |
在 GoF 的《Design Patterns》一書中共提到 23 種設計模式,有 18 種模式都使用了 VMI。所以 VMI 是瞭解 Design Patterns 的重要關鍵!
Creational | Structural | Behavioral |
---|---|---|
|
|
|
參考資料:
- http://stackoverflow.com/questions/11431185/what-is-the-use-of-java-virtual-method-invocation
- http://en.wikipedia.org/wiki/Dynamic_dispatch
- http://zh.wikipedia.org/wiki/虚函数_(程序语言)
- http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokevirtual
- http://msdn.microsoft.com/en-us/library/aa645767(v=vs.71).aspx
- https://developer.apple.com/library/mac/documentation/cocoa/conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html