歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Java:方法的虛分派(virtual dispatch)和方法表(method table)

Java:方法的虛分派(virtual dispatch)和方法表(method table)

日期:2017/3/1 10:17:54   编辑:Linux編程

背景知識:

java 字節碼基本框架,jvm基本框架

多態的機制。


Virtual Dispatch

首先從字節碼中對方法的調用說起。

java的bytecode中對方法的調用實現分為四種情況:

1.invokevirtual 為最常見的情況,包含virtual dispatch機制;

2.invokespecial是作為private和構造方法的調用,繞過了virtual dispatch;

3.invokeinterface的實現跟invokevirtual類似。

4.invokestatic是對靜態方法的調用。


其中最復雜的要屬 invokevirtual .

virtual dispatch機制會首先從 receiver(調用該方法的對象)的類的實現中查找對應的方法,如果沒找到,則去父類查找,直到找到函數並實現調用,而不是依賴於引用類型

下面是一段有趣的代碼。反映了virtual dispatch機制 和 一般的field訪問的不同。

  1. public class Greeting {
  2. String intro = "Hello";
  3. String target(){
  4. return "world";
  5. }
  6. }
  1. public class FrenchGreeting extends Greeting {
  2. String intro = "Bonjour";
  3. String target(){
  4. return "le monde";
  5. }
  6. public static void main(String[] args){
  7. Greeting english = new Greeting();
  8. Greeting french = new FrenchGreeting();
  9. System.out.println(english.intro + "," + english.target());
  10. System.out.println(french.intro + "," + french.target());
  11. System.out.println(((FrenchGreeting)french).intro + "," + ((FrenchGreeting)french).target());
  12. }
  13. }
運行的結果為
  1. Hello,world
  2. Hello,le monde
  3. Bonjour,le monde
其中的第二行是亮點。

對於intro這個filed的訪問,直接指向了父類中的變量,因為引用 類型為父類。

而對於target的方法調用,則是指向了子類中的方法,雖然引用類型也為父類,但這是virtual dispatch的結果,virtual dispatch不管引用類型的,只查receiver的類型。


既然 虛分派 機制是從receiver對象的子類開始查找,由此看來,對於一個覆蓋了父類中某方法的子類的對象,是無法調用父類中那個被覆蓋的方法的嗎?

在虛分派機制中這確實是不可以的。但卻可以通過invokespecial實現。如下代碼

  1. public class FrenchGreeting extends Greeting {
  2. String intro = "Bonjour";
  3. String target(){
  4. return "le monde";
  5. }
  6. public String func(){
  7. return super.target();
  8. }
  9. public static void main(String[] args){
  10. Greeting english = new Greeting();
  11. FrenchGreeting french = new FrenchGreeting();
  12. System.out.println(french.func());
  13. }
  14. }
func()就成功的調用了父類的方法target,雖然target已經被子類重寫了。怎麼實現的?讓我們看一看func方法中生成的字節碼:
  1. ALOAD 0: this
  2. INVOKESPECIAL Greeting.target() : String
  3. ARETURN
原來如此,它是通過invokespecial 指令來調用的。
Copyright © Linux教程網 All Rights Reserved