虚方法表与动态分派机制详解
在上兩篇中分別對方法重載【https://www.cnblogs.com/webor2006/p/9723289.html】和方法重寫【https://www.cnblogs.com/webor2006/p/9797506.html】在字節(jié)碼中的表現(xiàn)進(jìn)行了詳細(xì)的分析,其中得出如下結(jié)論:方法重載是靜態(tài)的,是編譯期行為;方法重寫是動態(tài)的,是運(yùn)行期行為。
這次繼續(xù)來舉一個綜合的例子,既有方法重載又有方法重寫,進(jìn)一步來闡述其靜態(tài)分派與動態(tài)分派的機(jī)制,如下:
那其結(jié)果是啥呢?咱們直接運(yùn)行一下:
分析一下:
咱們來看一下該代碼對應(yīng)的字節(jié)碼信息:
其實針對于方法調(diào)用動態(tài)分派的過程,虛擬機(jī)會在類的方法區(qū)建立一個虛方法表的數(shù)據(jù)結(jié)構(gòu)(virtual method table,也簡稱vtable)。針對于invokeinterface指令來說,虛擬機(jī)會建議一個叫做接口方法的數(shù)據(jù)結(jié)構(gòu)(interface method table,也簡單itable),其查找機(jī)制基本類似,下面用一個示例圖來對其進(jìn)行理解:
其中虛方法表vtable中每一項都存放的是特定方法實際真正的入口調(diào)用地址,其中有一種情況,就是子類Dog只繼承了Animal但沒有重寫過Animal父類的方法,如下:
?如果Dog子類重寫了父類的方法,那么當(dāng)然方法就會存在于Dog的虛方法表中啦。所以說對于Object類來說里面定義了很多的方法,但是實際我們編寫的類可能很多都沒有重寫它里面的方法,那么其虛方法表中都是存在Object當(dāng)中而非拷貝一份到我們具體子類當(dāng)中。
另外虛方法表vtable還有一點(diǎn)就是:只要是子類和父類的方法描述是一樣的,那么它們在父類和子類的索引是一樣的,這樣當(dāng)查找子類的方法時,由于索引跟父類是一模一樣的,則直接拿著子類該方法的索引到父類的方法表中的對應(yīng)的索引就直接可以定位到了,比較高效。一般虛方法表都是在類的連接階段【類加載有加載、連接、初始化階段】進(jìn)行的初始化。
下面來看一下這個程序,比較容易犯錯誤,看一下偽代碼:
如果說這樣調(diào)用:
肯定是木有問題的,很顯然就是Child的一個靜態(tài)調(diào)用,那如果這樣調(diào)用呢?
這個結(jié)果是編譯都通不過,不信的話咱們以之前的例子稍加修改一下:
為啥呢?其實這個從字節(jié)碼上就能夠解釋,對于這個程序:
其實會對應(yīng)于字節(jié)碼的invokevirtural指令,是靜態(tài)行為,其參數(shù)為Parent.test3(),就類似于:
而Parent類很明顯沒有定義test3()這個方法嘛,當(dāng)然就編譯不過了。
轉(zhuǎn)載于:https://www.cnblogs.com/webor2006/p/9814768.html
總結(jié)
以上是生活随笔為你收集整理的虚方法表与动态分派机制详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PowerShell字体颜色修改
- 下一篇: web第七周作业