下面幾個類用於確定今天晚餐要喝的酒以及酒的溫度
class Sommelier {
Wine recommend(String meal) {
}
}
abstract class Wine {
// 推薦酒的溫度
abstract float temperature();
}
class RedWine extends Wine {
// 紅酒的溫度通常略高於白酒
float temperature() { return
; }
}
class WhiteWine extends Wine {
float temperature() { return
; }
}
class Bordeaux extends RedWine {
float temperature() { return
; }
}
class Riesling extends WhiteWine {
// 繼承WhiteWine類的溫度
}
下面的例子利用上面的類推薦一種酒
void example
() {
Wine wine = sommelier
recommend(
duck
);
float temp = wine
temperature();
}
example
的第二個調用中
對於wine對象我們唯一可以肯定的是它是一個Wine
但可以是Bordeaux
也可以是Riesling或其他
另外
我們可以肯定wine對象不可能是Wine類本身的實例
因為Wine類是一個抽象類
編譯源代碼
源代碼中的wine
temperature()調用將變成
invokevirtual Wine/temperature ()F
(class文件實際包含的是該文本表示形式的二進制代碼
這種文本化的指令描述方法稱為Oolong方法)
它表示的是一個方法調用——一個普通的(虛擬)方法調用
而不是一個靜態調用
它調用的方法是Wine對象的temperature
右邊的
()F
參數稱為簽名(signature)
()F
這個簽名中的空括號表示方法不需要輸入參數
F表示返回值是一個浮點數
JVM執行到該語句時
它調用的不一定是Wine定義的temperature方法
實際上
在本例中
JVM不可能調用Wine定義的temperature方法
因為該temperature方法是一個虛擬方法
JVM首先檢查該對象所屬的類
尋找一個符合invokevirtual語句指定的名稱
簽名特征的方法
如果找不到
則檢查該類的超類
然後是超類的超類
直至找到一個合適的方法實現為止
在本例中
如果實際創建的對象是一個Bordeaux
則JVM調用Bordeaux類定義的temperature()F
該temperature()F方法將返回
如果對象是一個Riesling
JVM在Riesling類中找不到適當的方法
所以繼續查找WhiteWine類
在WhiteWine類中找到了一個合適的temperature()F方法
該方法的返回值是
因此
查找可用方法的過程就是沿著類的繼承樹通過字符串匹配尋找合適方法的過程
了解這一原理有助於理解哪些修改不至於影響二進制兼容性
首先
重新排列類裡面的方法顯然不會影響到二進制兼容性——這在C++程序中一般是不允許的
因為C++程序利用數值性偏移量而不是名稱來確定要調用的方法
延遲綁定的關鍵優勢正是在此
如果Java也使用方法在類裡面的偏移量來確定要調用的方法
必然極大地限制二進制兼容機制的發揮
即使極小的改動也可能導致大量的代碼需要重新編譯
·說明
也許有人會認為C++的處理方式要比Java的快
理由是根據數值性偏移量尋找方法肯定要比字符串匹配快
這種說法有一定道理
但只說明了類剛剛裝入時的情況
此後Java的JIT編譯器處理的也是數值性偏移量
而不再靠字符串匹配的辦法尋找方法
因為類裝入內存之後不可能再改變
所以這時的JIT編譯器根本無須顧慮到二進制兼容問題
因此
至少在方法調用這一點上
Java沒有理由一定比C++慢
其次
還有很重要的一點是
不僅僅編譯時需要檢查類的繼承關系
而且運行時JVM還要檢查類的繼承關系
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26162.html