1. 程式人生 > 實用技巧 >JVM07_棧幀之動態連結,方法的呼叫、動態語言型別和靜態語言

JVM07_棧幀之動態連結,方法的呼叫、動態語言型別和靜態語言

對於幀幀中的其他三部分:方法返回地址、動態連結和一些附加資訊,可以統稱為幀資料區

動態連結

在這裡插入圖片描述
java原始檔被編譯成class位元組碼檔案的時候,會把所有變數和方法的引用作為符號引用儲存到class檔案的常量池中
如下圖Constant pool, # 加數字就是符號引用。
也就是把當前class檔案需要的資源都做了符號引用。使用時就使用符號引用。
每一個棧幀中都存在一個動態連結,存的就是指向常量池的引用
所以動態連結也叫:指向執行時常量池的方法引用
在這裡插入圖片描述
在這裡插入圖片描述
class檔案中的常量池,在class執行起來後就放到 了JVM執行時資料區的方法區。

整體結構

一個執行緒中的執行時資料區,
包含PC暫存器、本地方法棧、虛擬機器棧等,在虛擬機器棧中,每個方法對應一個棧幀,

在棧幀的結構中,包含返回值、區域性變量表、運算元棧、動態連結。
當程式執行起來時,class檔案中的執行時常量池就放到了方法區中,那麼每個棧幀中就通過動態連結來引用常量池中的內容
在這裡插入圖片描述
常量池的作用
就是為了提供符號和常量,便於指令識別
如果沒有常量池中提供的符號引用其實也可以,那樣的話就需要在每一個class檔案都放一份所需要的變數和方法等,這樣class檔案會變得很冗餘,所以就出現了常量池,來減少記憶體消耗

方法的呼叫

在這裡插入圖片描述
編譯期可以確定的方法符號引用轉直接引用的過程是靜態連結,只能在執行期間確定的叫動態連結
class檔案中,一個方法中要呼叫其他變數和方法,使用的是符號引用,
當程式執行時,就要通過這個符號引用,找到相應的變數或方法

在這裡插入圖片描述
早期繫結和晚期繫結分別對應靜態連結和動態連結

通過檢視反編譯的位元組碼檔案,可以看到,構造器和方法都被放在了Methods下,所以說構造器和方法其實是同一個結構
在這裡插入圖片描述
所以在一個類中至少存在一個Methods,即預設的類的構造器

在這裡插入圖片描述
super(); 和 this(); 都屬於早期繫結,在編譯器就可以確定,並且執行時不會發生變化

在這裡插入圖片描述
而上邊這種,在方法引數中是一個父類或者介面的引用,這在編譯期是不能確定直接引用的,是動態連結,晚期繫結
在這裡插入圖片描述
多型就是來自於這種早期繫結和晚期繫結
java中的方法自動就有早期繫結和晚期繫結,如果不希望一個方法具有這種虛擬函式的性質,
那麼就可以使用final關鍵字,使得方法不能被重寫,在編譯期就已經確定了

C++中的虛擬函式對應java的晚期繫結,用來實現多型

非虛方法

在這裡插入圖片描述
靜態方法、私有方法、final方法,例項構造器、父類構造器都是非虛方法
子類物件的多型性使用前提:1、類的繼承或介面實現 2、方法的重寫

平時使用的第三方jar包,就是jar包中的類繼承了介面,然後進行具體的方法重寫,我們使用的就是第三方重寫的方法

方法呼叫指令

在這裡插入圖片描述
對於父類中的final修飾的方法,在子類中呼叫如果沒加super,位元組碼指令是invokevirtual,
加了super,指令是nivokespecial。
雖然指令是invokevirtual,但是因為是final修飾,所以子類不能重寫,也就是編譯期確定,就是非虛方法
在這裡插入圖片描述
showCommon()方法,子類中沒有重寫,那麼就是呼叫的父類的方法,但是這不保證子類不會重寫方法,所以編譯期確定不了
所以是虛方法
在這裡插入圖片描述

invokedynamic

在這裡插入圖片描述
lambda表示式中就使用了invokedynamic指令,使得java語言具備了動態語言的特性
通過lambda表示式建立的物件,只有最後經過方法重寫返回結果,在執行時才能確定型別。
在這裡插入圖片描述

動態語言型別和靜態語言

在這裡插入圖片描述
java屬於靜態語言,js、python屬於動態語言