JVM系列-方法調用的原理
最近從新看了一些JVM方面的筆記和資料,收穫頗豐,尤爲解決了長久以來心中關於JVM方法管理的一些疑問。下面介紹一下JVM中有關方法調用的知識。jvm
目的
方法調用,目的是選擇方法正確的執行版本,也就是找到方法的入口地址。學習
方法調用指令
方法調用的字節碼指令一共有五種,分別是:優化
- invokestatic:
- invokespecial:
-
方法:實例構造器
- 私有方法:private
- 父類中的方法
- invokevirtual
- invokeinterface
- invokedynamic
方法分類
非虛方法:
- 特色:
- 在類加載時期,有些方法的調用版本已經可以肯定,在類加載-解析階段,把這些方法的符號引用替換爲直接引用(即入口地址)。
- 包括:
- 類方法
-
方法
- 私有方法
- 父類中的方法
- final方法
即由invokestatic、invokespecial指令調用的方法,以及final修飾的方法,屬於非虛方法對象
虛方法:
- 特色:
- 包括:
即由invokevirtual調用的方法,除了final修飾的以外,都是虛方法繼承
調用方式
解析
- 定義:對於非虛方法,在類加載的時候已經能肯定這些方法的調用版本,在類加載的解析階段把符號引用替換爲直接引用,就是方法的入口地址
- 範圍:非虛方法
分派
靜態分派
- 定義:在編譯期,根據方法涉及的引用類型(包括參數列表的引用類型和方法的調用者的引用類型)來肯定方法調用的(初步)版本,並把相應的符號引用放在字節碼指令中,這個步驟叫作靜態分派
- 範圍:虛方法、非虛方法
- 應用:方法的重載
動態分派
- 定義:在運行時,根據對象的實際類型來肯定方法的調用版本,這個步驟叫作動態分派
- 範圍:虛方法
- 應用:方法的重寫
- 原理:
- 方法調用的部分字節碼指令:
- aload:在調用方法時,老是有該指令將實際類型的對象引用入棧
- 加載方法參數
- invoketual
- 先在棧頂取到實際類型的對象引用
- 根據方法的符號引用在本類中尋找,找不到的話依次向上在父類中找該方法
- 優化實現:在虛擬機中,虛方法表是動態分派的一種優化實現
- 虛方法表:
- 定義:類信息的一種,在類加載-準備階段完成初始化,存放在方法區
- 特色:
- 虛方法表中存儲方法的入口地址
- 子類中繼承但未重寫的方法,在子類的虛方法表中存放的入口地址,就是父類的虛方法表中的入口地址,指向父類的實現
- 在父子類中,相同符號引用的方法(重寫)的方法,其在各自虛方法表中的索引相同
- 解釋動態分派:
- 根據字節碼指令的符號引用,找到該方法在父類虛方法表中的索引
- 切換到實際類型的虛方法表,經過該索引,找到方法的入口地址
總結
主要內容在於方法調用的方式,即如何找到方法的入口地址的過程。索引
在這三種方式中,靜態分派發生在編譯期,解析發生在類加載時,動態分派發生在運行時。針對三者做用對象的不一樣可知,靜態分派是能夠和解析或動態分派同時發生的,如類方法依然能夠重載,重寫的方法也能夠重載。但解析和動態分派是不可共存的。接口
以上是個人分享,若有疑問或錯誤,請指出,一塊兒學習。ci
參考
《深刻理解Java虛擬機_JVM高級特性與最佳實踐-第3版》虛擬機