JVM 指令03__物件的建立和訪問指令
一、概述
Java 是面向物件的程式設計語言,虛擬機器平臺從位元組碼層面就對面向物件做了深層次的支援,有一系列的指令專門用於物件操作,這些指令可以進一步細分為建立指令、欄位訪問指令、陣列操作指令、型別檢查指令
二、建立指令
雖然類例項和陣列都是物件,但是 Jvm 對類例項和陣列的建立卻使用了不同的指令
2.1、建立類物件的指令
new: 該指令接收一個運算元,這個運算元是指向常量池的索引,該索引表示的是要建立物件的型別,new 指令執行完成之後,將建立在堆記憶體中物件的記憶體空間地址值壓入運算元棧中
newarray: 建立基本型別的一維陣列
anewarray: 建立引用型別的一維陣列
multianewarray: 建立多維陣列
案例:
三、欄位訪問指令
物件建立完成之後,就可以通過物件訪問指令來獲取物件例項的欄位或陣列例項中的陣列元素
訪問靜態欄位: getstatic、putstatic
訪問非靜態欄位: getfield、putfield
getxx 指令表示將 值/物件 壓入運算元棧,putxx 指令表示將 值/物件 彈出運算元棧進行操作
四、陣列操作指令
陣列操作指令主要有 xastore 和 xaload
xastore: 將陣列物件的記憶體地址值從區域性變量表載入進入運算元棧
xaload: 將運算元棧中的值儲存到堆空間陣列物件的指定索引位置
資料型別 | 載入指令 | 儲存指令 |
byte / boolean |
baload | bastore |
short | saload | sastore |
char | caload | castore |
int | iaload | iastore |
long | laload | lastore |
float | faload | fastore |
double | daload | dastore |
reference | aaload | aastore |
案例
public class Client { public static void main(String[] args) { int[] intArr = new int[3]; intArr[2] = 5; System.out.println(intArr[2]); } }
對應位元組碼檔案
0 iconst_3
1 newarray 10 (int)
3 astore_1
4 aload_1
5 iconst_2
6 iconst_5
7 iastore
8 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
11 aload_1
12 iconst_2
13 iaload
14 invokevirtual #3 <java/io/PrintStream.println : (I)V>
17 return
指令 1、iconst_3: 將常量 3 壓入運算元棧
指令 2、 newarray 10 (int): 將運算元 3 彈出運算元棧,在堆記憶體中為陣列開闢出一塊長度為 3 的空間,並且該陣列元素的型別是 int,為陣列進行預設初始化,完成之後將該陣列空間的記憶體地址壓入運算元棧
注 newarray 後面的 10 代表的是陣列的型別,10 的型別就是 int 型別的陣列,具體的官方 Jvm 指令定義型別如下
指令 3、astore_1: 將運算元棧頂的元素彈出,存入區域性變量表下標為 1 的位置,該地址直接指向堆空間中陣列的記憶體區域
指令 4、aload_1: 將區域性變量表中下標為 1 的運算元壓入運算元棧中
指令 5、iconst_2: 將常數 2 壓入運算元棧中
指令 6、iconst_5: 將常數 5 壓入運算元棧中
指令 7、iastore: 將運算元棧 5、2、0x3e86 彈出運算元棧,為陣列第 2 個索引位置的元素進行顯示賦值 5
通過 0x3e86 找到陣列物件在堆空間的實際記憶體位置,2 作為陣列下標索引,5 作為值為陣列進行賦值操作
指令 8、getstatic: 通過符號引用 #2 在常量池中找到靜態欄位 System.out,並將其壓入運算元棧中
指令 9、aload_1: 將區域性變量表索引下標為 1 的運算元壓入運算元棧
指令 10、iconst_2: 將常數 2 壓入運算元棧
指令 11、iaload: 將運算元棧的棧頂運算元(2)和次棧頂運算元(0x3e86) 彈出運算元棧,通過 0x3e86 定位到陣列在堆空間的實際位置,通過 2 定位到該陣列索引為 2 的元素,將該元素的值壓入運算元棧中
指令 12、invokevirtual #3: 通過符號引用找到常量池中對應的方法資訊<println : (I)V>,main 方法棧幀中運算元彈出,接著在虛擬機器棧中開闢 println 方法棧幀
輸出結果 5 之後,println 方法棧幀出棧
main 方法執行完成之後 main 方法棧幀出操作數棧
堆空間的陣列物件無任何引用指向,等待垃圾回收器回收
五、型別轉換指令
型別檢查指令主要有 instanceof 和 checkcast
instanceof: 判斷物件是否是某一個類的例項,它會將判斷後的結果壓入運算元棧當中
checkcast: 檢查型別是否可以進行強制型別轉換,如果可以進行轉換那麼 checkcast 指令不會改變運算元棧,否則會丟擲 ClassCastException