JVMClass詳解之二Method位元組碼指令
JVM Class詳解之一中我們介紹了Class檔案的結構和如何使用16進位制編輯器讀懂class檔案。
今天我們來繼續一起下Class檔案中Method方法中經過java編譯器編譯後的Method位元組碼指令是什麼樣子的
JVM有哪些位元組碼指令
首先我們需要了解JVM有哪些位元組碼指令
第一類load型別
是將本地變數中的資料推送入棧中 (什麼是本地變數我們後面聊)
iload,iload_,lload,lload_,fload,fload_,dload,dload_,aload,aload_
iload_0:將第一個int型本地變數推送至棧頂
iload中i表示為int型(l為long,f為float,d為double ,a為引用型別),load表示動作為load,
後面的指令大多都是這種結構,先是宣告運算元型別,再說明具體動作。
同理 fload:將本地變數的float型資料推送棧頂
第二類store
load是從本地變數到棧頂,store是從棧頂到本地變數
istore,istore_,lstore,lstore_,fstore,fstore_,dstore,dstor_,astore,astore_
istore:將棧頂int型數值存入制定陣列的指定索引位置
第三類push,const
除了本地變數到棧頂,還有常量到棧頂
bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_,lconst_,fconst_,dconst_
ldc:將int,float或String型常量從常量池中推送至棧頂
iconst_0:將int型0推送至棧頂
第四類 算數操作
加:iadd,ladd,fadd,dadd :將棧頂兩個數值相加並將將結果壓入棧頂
減:is ,ls ,fs ,ds
乘:imul,lmul,fmul,dmul
除:idiv,ldiv,fdiv,ddiv
餘數:irem,lrem,frem,drem
取負:ineg,lneg,fneg,dneg
移位:ishl,lshr,iushr,lshl,lshr,lushr
按位或:ior,lor
按位與:iand,land
按位異或:ixor,lxor
型別轉換:i2l,i2f,i2d,l2f,l2d,f2d(放寬數值轉換)
i2b,i2c,i2s,l2i,f2i,f2l,d2i,d2l,d2f(縮窄數值轉換)
這個很簡單的顧名思義哈哈。
第五類 比較操作
lcmp:比較棧頂兩個long型數值的大小,並將結果(1,0,-1)壓入棧頂
fcmpl:比較棧頂兩個float型數值的大小,並將結果(1,0,-1)壓入棧頂,當其中一個為NaN,將-1壓入棧頂
fcmpg:。。。。。其中一個為NaN,將1壓入棧頂
dcmpl
dcmpg
第六類 跳轉
ifeq:當棧頂int型數值等於0時跳轉
ifne:當棧頂int型數值不等於0時跳轉
iflt:當棧頂int型數值小於0時跳轉
ifge:大於等於0
ifgt:大於0
ifle:小於等於0
if_icmpeq:比較棧頂兩個int大小,等於0跳轉
if_icmpne:不等於0跳轉
。。。
goto:無條件跳轉
goto,goto_w,jsr,jsr_w,ret
ifnull:為null時跳轉
ifnonnull:不為null時跳轉
finally關鍵字的實現使用:jsr,jsr_w,ret
第七類 返回操作
ireturn:從當前方法返回int
lreturn:從當前方法放回long
。。。
return:從當前方法返回void
第八類 Class的相關操作
getstatic:獲取指定類的靜態域,並將其值壓入棧頂
putstatic:為指定的類的靜態域賦值
getfield:獲取指定類的例項域,並將其值壓入棧頂
pufield:為指定類的例項域賦值
invokevirtual:呼叫例項方法
invokespecial:呼叫超類構造方法,例項初始化方法沒有方法
invokestatic:呼叫靜態方法
invokeinterface:呼叫介面方法
invokedynamic:呼叫動態方法
new:建立一個物件
newarray:建立一個指定的原始型別陣列
anewarray:建立一個引用型的陣列,並將其引用值壓入棧頂
arraylength:獲取陣列的長度並壓入棧頂
athrow:將棧頂的異常丟擲
checkcast:檢查型別轉換,檢查未通過會丟擲ClassCastException
instanceof:檢查是否是指定的類的例項,如果是,將1壓入棧頂,不是將0壓入棧頂
monitorenter:獲取物件的鎖,用於同步方法或者同步塊
monitorexit:釋放物件的鎖
wide:擴充套件本地變數的寬度
好至此主要的指令已經介紹完畢,怎麼分類仁者見仁啦。
HelloWorld搞起
public class HelloWorldMethod{
public intaddNumber(int a,int b){
if(a<0){
return -1;
}
if( b < 0 ){
return -1;
}
int c = a + b;
returnc;
}
}
這個intAddMethod方法傳入兩個int,判斷是否小於0,如果小於返回-1,都不小於返回相加值
我們通過javap -verbose HelloWorldMethod.class 檢視位元組碼指令
我們按照指令一條一條看
0:iload_1:將本地變數中第一個int (a)載入到棧頂
為什麼是a呢,我們再看LovalVariableTable。每個方法都有LocalVariableTable。是本地變數表。我們可以看到在本地變數表中的第一個int就是a
1:ifge:判斷棧頂的int是否大於0如果大於將1壓入棧頂,如果不大於將0壓入棧頂
分支1:如果當前值不大於0將0壓入棧頂,
分支2:如果當前值大於0跳轉到指令6
4:iconst_m1:將整型-1壓入棧頂
5:ireturn
6:iload_2:將本地變數彙總第二個int(b)壓入棧頂
7:ifge:判斷棧頂的int是否大於0
分支3:如果當前值不大於0,將棧頂壓入0
分支4:如果當前值大於0,將1壓入棧頂,並跳轉到執行12執行
10:iconst_m1:將int -1壓入棧頂
11:ireturn:返回棧頂int值
12:iload_1:將本地變數第一個int壓入棧頂(a)
13:iload_2:將本地變數第二個int壓入棧頂(b)
14:iadd:將棧頂的兩個int相加並將結果壓入棧頂 a+b
15:istore_3:將棧頂的int值,存入本地變數表中第三個int,第三個int為c,將結果付給了c
16:iload_3:將本地變數中的第三個int壓入棧頂,取出c
17:ireturn:將棧頂的第一個int返回
LineNumberTable
Code中 還有另外一個東西
這個是什麼,這個是LineNumberTable,其中記錄了編譯出來的位元組碼指令和原始碼的對應關係
這個屬性不是很重要。另外就是一個原始碼會對應多條指令的
好了至此我們就知道了我們JAVA檔案編譯後的Method中有什麼東西,JVM又是怎樣讀取位元組碼指令做相應操作的了。
相關文章
- 位元組碼詳解
- 位元組碼指令
- Java位元組碼指令Java
- 位元組碼檔案結構詳解
- Java位元組碼指令表Java
- 詳解Android Gradle生成位元組碼流程AndroidGradle
- Java Class 位元組碼檔案結構詳解Java
- 什麼是位元組碼?python位元組碼詳細介紹!Python
- C/C++位元組詳解C++
- Class檔案結構&位元組碼指令
- 位元組碼指令分析 ++i 和 i++
- JVM 內部原理(七)— Java 位元組碼基礎之二JVMJava
- jvm 虛擬機器位元組碼指令表JVM虛擬機
- 深入淺出JVM(十)之位元組碼指令(下篇)JVM
- 【JVM原始碼解析】模板直譯器解釋執行Java位元組碼指令(上)JVM原始碼Java
- Java 位元組碼Java
- nmap指令碼詳解指令碼
- 位元組碼基礎
- Python struct(位元組流,組包拆包實現)模組詳解PythonStruct
- C/C++ 結構體位元組對齊詳解C++結構體
- C語言:記憶體位元組對齊詳解C語言記憶體
- 方法引用(Method reference)和invokedynamic指令詳細分析
- 深入理解JAVA虛擬機器學習筆記18——位元組碼指令2(運算指令)Java虛擬機機器學習筆記
- JAVA動態位元組碼Java
- 位元組編碼轉換
- 理解 Python 位元組碼Python
- 字元,位元組和編碼字元
- 位元組碼檔案解剖
- 【Java】JVM位元組碼分析JavaJVM
- 硬核萬字長文,深入理解 Java 位元組碼指令(建議收藏)Java
- Shell指令碼之sed詳解指令碼
- Linux Shell指令碼系列之二Linux指令碼
- 位元組跳動極高可用 KV 儲存系統詳解
- c++記憶體中位元組對齊問題詳解C++記憶體
- Android 位元組碼插樁Android
- 輕鬆看懂Java位元組碼Java
- Python 位元組碼介紹Python
- Java位元組碼忍者禁術Java