JVM解釋方法的執行

前言

class文件被加載到內存中,JVM如何執行類方法?下面我們來看一下方法的人生。

重寫與重載

重寫與重載對與我們並不陌生,java作爲面向對象的語言,有封裝、繼承、多態三大特性,而重寫是多態的一個體現,而重載是參數不同的同名方法。

重載
但是對於JVM並沒有重載這個概念,在源代碼編譯時就已經指定了實際的方法,那麼指定的具體過程是怎麼樣的呢?編譯器根據傳入參數的聲明類型(注意與實際類型區分)來選擇重載,選取分爲三個階段:

  1. 不考慮自動拆裝箱以及可變長參數的情況下選取方法
  2. 允許自動拆裝箱,但是不允許可變長參數
  3. 允許自動拆裝箱和可變長參數

重寫

而重寫會根據調用者的動態類型選取實際的目標方法。JVM識別方法主要通過類名、方法名、以及方法描述符(方法描述符由方法的參數類型以及返回類型構成)。JVM對於方法重寫的判定也基於方法描述符,子類定義了與父類非私有、非靜態的方法、當方法描述符相同時判定爲重寫。

方法的調用

字節碼中與調用相關的指令有五種:

  • invokestatic:調用靜態方法,

  • invokespecial:調用私有實例方法,構造器,以及supper調用父類的實例方法或構造器和所以實現接口的默認方法

  • invokevirtual:調用非私有實例方法

  • invokeinterfance:調用接口方法

  • invokedynamic:調用動態方法

編譯過程中,不知道目標方法的內存地址,用符號引用來表示,符號引用包括目標方法的類或接口名字,以及目標方法的方法名和方法描述符,符號引用存入class文件的常量池中,根據目標方法分爲接口引用和非接口引用,在執行解析時會將符號引用替換爲實際引用。

非接口引用,假如符號引用指向類C:

  • 在C中查找符號名字及描述符的方法
  • 如果沒有找到,C的父類中搜索,一直到Object
  • 如果沒有找到,C的直接實現或間接實現的接口搜索,這一步得到的目標方法是非私有非靜態,如果目標方法在間接實現的接口中,則需滿足C與該接口之間沒有其他符合條件的目標方法,如果多個符符合,任意返回

接口引用,假設執行接口I:

  • I中查找符合名字和描述符的方法
  • 在Object的公有實例中搜索
  • 在I的超接口中搜索,要求與非接口的引用一致

經過對符號引用的的解析,符號引用解析成了實際引用,可以靜態綁定的方法,實際引用是指向方法的指針。需要動態綁定的方法調用,實際引用是一個方法表的索引。

方法表

在寫類加載機制的那篇博客中曾經說過,在類加載的準備階段有的虛擬機會生成一個類的方法表,這個方法表就是用來動態確定方法調用的。

方法表其實就是一個數組,每個元素都指向當前類或者祖先類中非私有的實例方法,但是方法表還需要滿足兩個條件:子類包含父類的所有方法,並且子類重寫的方法與父類的方法索引要相同。在實際的調用過程中,JVM根據調用者的實際類型在方法表中獲取目標方法

當然方法表作爲定位目標方法的一種手段僅存在解析執行中,在即時編譯下還有更好的方法比如:內聯緩存、方法內聯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章