JVM 方法呼叫之動態分派 詳解

2022-10-07 07:48:10 字數 1945 閱讀 2490

1. 動態分派

乙個體現是重寫(override)程式設計客棧。下面的**,執行結果很明顯。

public class app

} class super

public void f(int i)

}class sub extends super

@overwww.cppcns.comride

public void f(int i)

public void f(char c)

}最終輸出sub : f();

那麼虛擬機器是怎麼做到動態分派的呢?

不同的虛擬機器有不同的實現,最常用的是使用虛方法表(virtual method table)

2. 虛方法表

對於super和sub類,虛方法表大致如下:(靈魂畫師)

上面的靈魂畫作是什麼意思呢?

虛方法表中存放著各個方法的實際入口位址。如果某個方法在子類中沒有被重寫,那子類的虛方法表裡面的位址入口和父類相同簽名的方法的位址入口是一致的,都指向父類的實現入口。如果子類中重寫了這個方法,子類方法表中的位址將會替換為向子類實現版本的入口位址。

從上圖主要得出幾個信程式設計客棧息:

a. 上圖的大部分方法,子類super和sub均沒有重寫,那麼都指向父類object的型別資料。f()和f(int)方法,父類子類都實現了,那麼兩者就指向不同的實現位址。f(char)只在子類定義實現,自然指向子類的型別資料。

b. 為了程式實現上的方便,具有相同簽名的方法,在父類,子類的虛方法表中都應當具有一樣的索引序號,這樣當型別變換時,僅需要變更查詢的方法表,就可以從不同的虛方法表中按索引轉換出所需要的入口位址。

3. 例項分析

以本文開頭的**進行分析。通過j**ap命令檢視main方法的指令。

其中的invokevirtual指令詳細呼叫過程是這樣的:

1)指令中的#19指的是app類的常量池中第19個常量表的索引項。這個常量表(constatn_methodref_info)記錄的是方法f()資訊的符號引用,jvm首先根據這個符號引用找到呼叫方法f()的類的全限定名com.khlin.super,這是因為變數object被宣告為super型別。

2) 在super型別的方法表中查詢方法f(),如果找到,則將方法f()在方法表中的索引項(具體值我不了解,這裡將其記為index) 記錄到app類的常量池中第19個常量表中(常量池解析)。因此,如果super型別方法表中沒有f(),那麼即使sub型別的方法表有該方法,也會報編譯失敗。

3)在呼叫invokevirtual指令前有乙個aload_1指令,它會將開始建立中堆中的sub物件的引用壓入運算元棧。然後invokevirtual指令會根據這個sub物件的引用首先找到堆中的sub物件,然後進一步找到sub物件所屬型別的方法表。

4)這時,通過2)查詢的index,可以定位到sub型別方法表中的f()方法,然後通過直接位址找到該方法位元組碼所在的記憶體空間。這就是父類和子類相同簽名的方法索引序號一致的用處。

4. 綜合考慮:乙個可能想錯的例子

將本文開頭的**裡的main方法稍作修改,呼叫其他的方法。

public static void main(string args)

結果將輸出sub : f(int)

明明sub方法裡有完全一樣型別的f(char)方法,卻呼叫的是f(int).

相信通過前面的學習,已經可以明白原因了。

在object.f(c)呼叫時,虛擬機器先到super類的方法表裡,查詢最為合適的方法。

super類裡沒有剛好引數為char的f(char)方法,按照前面靜態分派和引數型別自動轉換的學習,可以知道,編譯器使用了除了f(char)之外最為合適的方法f(int)。獲取到索引後,通過索引到實際物件的sub方法表裡找到f(int)方法,最終執行的就是sub類的f(int)方法。

該方法的位元組碼指令證明了上述的論證。

本文標題: jvm 方法呼叫之動態分派(詳解)

本文位址: /ruanjian/j**a/189468.html

JVM方法分派

方法靜態分派演示 方法靜態分派演示 created by tiantao on 15 2 9.public class staticdispatch static class man extends human static class woman extends human public void...

深入理解JVM之七 靜態分派與動態分派

public class o static class b extends a static class c extends a public void a a a public void a b b public void a c c public static void main string ...

JVM方法呼叫指令

終於把inside jvm這本看完了,好久沒這麼細緻的看一本書了。好多人都寫了文章討論jvm如何實現多型的,我只是簡單做個筆記。類的位元組碼結構有個常量池,其中就存放了這個類中呼叫的方法的符號引用,這些符號引用實際上是放在一些特殊型別 constant nameandtype info 的常量池入口...