JVM系列-方法調用的原理

JVM系列-方法調用的原理

最近從新看了一些JVM方面的筆記和資料,收穫頗豐,尤爲解決了長久以來心中關於JVM方法管理的一些疑問。下面介紹一下JVM中有關方法調用的知識。jvm

目的

方法調用,目的是選擇方法正確的執行版本,也就是找到方法的入口地址。學習

方法調用指令

方法調用的字節碼指令一共有五種,分別是:優化

  1. invokestatic:
    • 類方法:static
  2. invokespecial:
    • 方法:實例構造器
    • 私有方法:private
    • 父類中的方法
  3. invokevirtual
    • 虛方法
    • final修飾的方法
  4. invokeinterface
    • 接口方法
  5. invokedynamic
    • 用於動態語言支持

方法分類

非虛方法:

  1. 特色:
    • 在類加載時期,有些方法的調用版本已經可以肯定,在類加載-解析階段,把這些方法的符號引用替換爲直接引用(即入口地址)。
  2. 包括:
    1. 類方法
    2. 方法
    3. 私有方法
    4. 父類中的方法
    5. final方法

即由invokestatic、invokespecial指令調用的方法,以及final修飾的方法,屬於非虛方法對象

虛方法:

  1. 特色:
    • 在類加載時期,沒法肯定方法最終的調用版本
  2. 包括:
    • 非非虛方法

即由invokevirtual調用的方法,除了final修飾的以外,都是虛方法繼承

調用方式

解析

  1. 定義:對於非虛方法,在類加載的時候已經能肯定這些方法的調用版本,在類加載的解析階段把符號引用替換爲直接引用,就是方法的入口地址
  2. 範圍:非虛方法

分派

靜態分派

  1. 定義:在編譯期,根據方法涉及的引用類型(包括參數列表的引用類型和方法的調用者的引用類型)來肯定方法調用的(初步)版本,並把相應的符號引用放在字節碼指令中,這個步驟叫作靜態分派
  2. 範圍:虛方法、非虛方法
  3. 應用:方法的重載

動態分派

  1. 定義:在運行時,根據對象的實際類型來肯定方法的調用版本,這個步驟叫作動態分派
  2. 範圍:虛方法
  3. 應用:方法的重寫
  4. 原理:
    1. 方法調用的部分字節碼指令:
      1. aload:在調用方法時,老是有該指令將實際類型的對象引用入棧
      2. 加載方法參數
      3. invoketual
        1. 先在棧頂取到實際類型的對象引用
        2. 根據方法的符號引用在本類中尋找,找不到的話依次向上在父類中找該方法
    2. 優化實現:在虛擬機中,虛方法表是動態分派的一種優化實現
      1. 虛方法表:
        1. 定義:類信息的一種,在類加載-準備階段完成初始化,存放在方法區
        2. 特色:
          1. 虛方法表中存儲方法的入口地址
          2. 子類中繼承但未重寫的方法,在子類的虛方法表中存放的入口地址,就是父類的虛方法表中的入口地址,指向父類的實現
          3. 在父子類中,相同符號引用的方法(重寫)的方法,其在各自虛方法表中的索引相同
      2. 解釋動態分派:
        1. 根據字節碼指令的符號引用,找到該方法在父類虛方法表中的索引
        2. 切換到實際類型的虛方法表,經過該索引,找到方法的入口地址

總結

主要內容在於方法調用的方式,即如何找到方法的入口地址的過程。索引

在這三種方式中,靜態分派發生在編譯期,解析發生在類加載時,動態分派發生在運行時。針對三者做用對象的不一樣可知,靜態分派是能夠和解析或動態分派同時發生的,如類方法依然能夠重載,重寫的方法也能夠重載。但解析和動態分派是不可共存的。接口

以上是個人分享,若有疑問或錯誤,請指出,一塊兒學習。ci

參考

《深刻理解Java虛擬機_JVM高級特性與最佳實踐-第3版》虛擬機

相關文章
相關標籤/搜索