執行引擎執行java代碼執行可能會 解釋執行(通過解釋器) 和編譯執行(通過即時編譯器產生本地代碼) 也可能
兩者都用
棧幀 :用於支持虛擬機進行方法調用和方法執行的數據結構,是虛擬機棧的棧元素,存儲了:方法的局部變量表、操作數棧、動態連接和方法返回地址
一個棧幀分配的大小取決於jvm的實現
局部變量表:是一組變量值存儲空間,用於存放方法參數以及方法內部定義的局部變量,在編譯階段在Code屬性中確定了容量
以變量槽(Variable Slot)爲最小單位,可以存放boolean,byte,char,short,int,float,reference
,returneAddress這八種數據類型即可,一般而言32位 long,double佔兩個slot!!!
Slot可重用,一般而言,噹噹前字節碼PC計數器的值已經超過了某個變量的作用域,那麼就可以給其他的變量使用
操作數棧,編譯的時候Code屬性確定深度,每一個元素可以是任意的Java數據類型,64位數據類型佔兩個棧容量。
通常優化爲兩個棧幀會有重複部分,即棧幀一的操作數棧的一部分與棧幀二的局部變量表的一部分共享數據!
棧幀信息:動態連接,方法返回地址,其他附加信息。
方法調用:確定被調用方法的版本(即確認調用哪一個方法),不一定要確認方法的直接引用
解析: 編譯期可知,運行期不變的 方法主要有 靜態方法和私有方法,這兩種會直接解析出直接引用
invokestatic,invokespecial,invokevirtual,invokeinterface,invokedynamic
只要被invokestatic,invokespecial指令調用的方法都可以在解析階段確定唯一的調用版本,符合這個條件的有靜態方法
,私有方法,實例構造器,父類方法。類加載的時候就會把符號引用解析爲直接引用,這些方法稱爲非虛方法(被final
修飾也是)。
分派: 多態
1.靜態分派:靜態類型(外觀類型),實際類型 ,應用於重載選擇方法
jvm重載通過參數的靜態類型作爲判定。變長參數優先級最低
char->int->long->float->double->Character->接口->Object->變長數組
2.動態分派 根據實際類型在選擇執行方法
3.單分派與多分派
java是一門靜態多分派,動態單分派的語言
編譯器的選擇過程爲靜態分派過程,依據有兩點:1.靜態類型是什麼,2.方法參數是什麼
運行階段虛擬機選擇爲動態分派,在編譯階段已經確定了方法簽名,傳過來的參數爲QQ,不
管QQ是什麼樣的,是“奇瑞”還是“騰訊”
根據一個宗量的類型進行方法的選擇稱爲單分派
根據多於一個宗量的類型對方法的選擇稱爲多分派
再看定義:方法的接受者與方法的參數統稱爲方法的宗量。
下面看看編譯階段編譯器的選擇過程,也就是靜態分派的過程。
這個時候,選擇目標方法依據兩點:
一個是靜態類型Father和Son,
二是方法參數Ipad和Iphone。
這次選擇的結果的最終產物是產生了兩條invokevirtual指令,兩條指令的參數分別爲常量池中指向Father.hardChoice(ipad)及Father.hardChoice(iphone)方法的符號引用。因爲是根據兩個宗量進行選擇,所以Java語言的靜態分派屬於多分派類型。
再看看運行階段虛擬機的選擇,也就是動態分派的過程。
在執行son.hardChoice(new Ipad())這句代碼時,由於編譯期已經決定目標方法的簽名必須爲hardChoice(Ipad),虛擬機不會關心傳遞過來的參數到底是什麼,因爲這時參數的靜態類型、實際類型都對方法的選擇不會構成任何影響,唯一可以影響虛擬機選擇的因素只有此方法的接受者的實際類型到底是Father還是Son。因爲只有一個宗量作爲選擇一句,所以Java語言的動態分派屬於單分派類型。
4.jvm動態分派的實現
由於元數據量大,處於性能的考慮,會有一個虛方法表來記錄改類的方法用於查找