1. 程式人生 > >《深入理解java虛擬機器》學習-第八章-虛擬機器位元組碼執行引擎-方法呼叫

《深入理解java虛擬機器》學習-第八章-虛擬機器位元組碼執行引擎-方法呼叫

1.概述
① 方法呼叫並不等同於方法執行,方法呼叫階段唯一的任務就是確定被呼叫方法的版本(即呼叫哪一個方法),暫時還不涉及方法內部的具體執行過程。
② 一切方法呼叫在Class檔案裡面儲存的都只是常量池中的符號引用,而不是方法在實際執行時記憶體佈局的入口地址(即直接引用);
③ 優點:更強大的動態擴充套件能力;
④ 缺點:使java方法呼叫過程複雜起來,需要在類載入期間,甚至到執行期間才能確定目標方法的直接引用;

2.解析
① 解析成立前提條件:方法在程式真正執行之前就有一個可確定的呼叫版本,並且這個方法的呼叫版本在執行期是不可變的;
② 定義:呼叫目標在程式程式碼寫好、編譯器執行編譯時就必須確定下來,這類方法的呼叫稱為解析;
③ “編譯期可知,執行期不變”,符合此要求的主要包括靜態方法和私有方法,它們都不可能通過繼承或別的方式重寫其他版本,因此他們都適合在類載入階段進行解析;
④ java虛擬機器提供5條方法呼叫位元組碼指令:invokestatic(呼叫靜態方法)、invokespecial(呼叫例項構造器<init>方法、私有方法和父類方法)、invokevirtual(呼叫所有的虛方法)、invokeinterface(呼叫介面方法,會在執行時再確定一個實現此介面的物件)、invokedynamic(先在執行時動態解析出呼叫點限定符所引用的方法,然後再執行該方法)
⑤ 以上前4條呼叫指令,分派邏輯是固化在jvm內部的,而最後一個的分派邏輯是由使用者所設定的引導方法決定的;
⑥ 非虛方法:只要能被invokestatic和invokespecial指令呼叫的方法,都可以在解析階段中確定唯一的呼叫版本,符合這個條件的有靜態方法、私有方法、例項構造器、父類方法四類,他們在類載入的時候就會把符號引用解析為該方法的直接引用。這些方法被稱為非虛方法,與之相反,其他方法稱為虛方法(除去final方法);
⑦ final修飾的方法:也是非虛方法,使用invokevirtual指令呼叫,無法被覆蓋,無其他版本,無需對方法接收者進行多型選擇(或者說多型選擇結果唯一);
⑧ 解析一定是個靜態的過程,編譯期就完全確定,在類裝載的解析階段就會把涉及的符號引用全部轉變為可確定的直接引用,不會延遲到執行期去完成;

3.分派
① 分派呼叫可能是靜態的,也可能是動態的,根據分派依據的宗量數可分為單分派和多分派,這兩類分派方式的兩兩組合就構成了靜態單分派、靜態多分派、動態單分派、動態多分派4種分派組合情況;
② 分派呼叫過程揭示java多型性特徵的一些最基本體現,如過載和重寫的實現;
③ 靜態分派:所有依賴靜態方法來定位方法執行版本的分派動作稱為靜態分派。其典型應用是方法過載,發生在編譯階段;
④ 過載優先順序:以字元(‘a’)為例,優先順序由高到低為char-int-long-Character-Serializable-Object-char...,注意最後一個是不定長引數;
⑤ 動態分派:與多型性的另一個重要體現——重寫有關,我們把這種在執行期根據實際型別確定方法執行版本的分派過程稱為動態分派;
⑥ 宗量:方法的接收者與方法的引數統稱為方法的宗量,根據分派基於多少種宗量,可以將分派劃分為單分派和多分派兩種,單分派是根據一個宗量對目標方法進行選擇,多分派則是根據多餘一個宗量對目標方法進行選擇;
⑦ java語言的靜態分派屬於多分派型別,動態則是單分派(未釋出JDK1.8時,JDK1.7新增的invokedynamic指令是方法呼叫指令中最複雜的一條);(書中有示例)
⑧ 虛擬機器動態分派的實現:最常用的“穩定優化”手段就是為類在方法區中建立一個虛方法表,使用虛方法表索引來代替元資料查詢以提高效能。除此之外還會使用內聯快取和基於“型別繼承關係分析”技術的守護內聯兩種非穩定的“激進優化”手段來獲得更高的效能;

4.動態型別語言支援(JDK7的invokedynamic指令)
① 動態型別語言特徵:型別檢查的主體過程是在執行期而不是編譯期,相對的,在編譯期就進行型別檢查過程的語言(C++和java等)就是最常用的靜態型別語言;
② JDK1.7與動態型別
③ java.lang.invoke包
④ invokedynamic指令:每一處含有此指令的位置都稱作動態呼叫點