中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java中ASM框架有什么用

發布時間:2021-10-11 10:59:26 來源:億速云 閱讀:124 作者:小新 欄目:編程語言

這篇文章主要為大家展示了“java中ASM框架有什么用”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“java中ASM框架有什么用”這篇文章吧。

簡介

ASM是java字節碼操作框架,利用該框架可以達到動態修改java運行對象代碼的目的,也可以實現動態代理等功能;

線程和棧幀

要了解ASM字節碼操作,先要熟悉jvm線程與棧幀結構,jvm開辟一個線程,便會開辟屬于這個線程虛擬機棧,本地方法棧,程序計數器,其主要作用如下:

  • 虛擬機棧:以棧幀為基本單位,一個棧幀的開始地址代表一個方法的入口,棧幀里面有操作數棧,局部變量表,動態鏈接,方法出口,其他信息;其說明如下:

    • 操作數棧::用來存放需要cpu進行計算的基本類型和對象引用,以4個字節的slot為基本單位;

    • 局部變量表:存放當前棧幀涉及到的變量表,以4個字節的slot為基本單位;

    • 動態鏈接: 存放執行常量池的引用,可以實現當前方法的動態鏈接;

    • 方法出口:用于方法的返回,可以是異常的發生,return操作指令等等;

  • 本地方法棧:類似于虛擬機棧,但是保存的是java本地代碼庫的一些信息;

  • 程序計數器:保存該線程指令執行位置,待下次調度時可以接著往下執行;
    具體如下圖所示:

     

     

         

    線程虛擬機棧結構.png

基本類型

java字節碼中的類型表達和java代碼是不一樣的,在java字節碼中利用如下符號來表達基本類型:

java類型type含義
booleanZ布爾
charC字符
byteB字節
shortS短整型
intI整型
longJ長整型
floatF浮點數
referenceL類的引用
voidV
doubleD雙精度浮點型
ObjectLjava/lang/Object;對象
int[][I整型數組
Object[][][[Ljava/lang/Object;對象數組

注: L+className;代表某類的引用(";"不能省略)

字節碼實例:

Java代碼字節碼表示注釋
double[][][[D
Object run(int i,double d,Thread t)(IDLjava/lang/Thread)Ljava/lang/Object;(方法參數字節碼類型)方法返回參數類型

字節碼指令操作

字節碼指令操作其實主要操作局部變量表和操作數棧,具體流程是:load局部變量到操作數棧,然后給cpu下達執行指令,然后將操作數棧棧頂元素彈出,從而實現一個操作;
字節碼指令都有一定的格式:[type+]op["_"+value];

其中type根據基本類型可以為:i(int 整數),s(short 短整數),b(byte 字節),c(char字符),l(long長整數),d(double雙精度浮點數),f(float 浮點數),a(reference 引用);
value指的是操作數,如果操作數為負數時需要添加'm"前綴,例如iconstant_m1表示將-1壓棧;如果操作數值超過一定大小,則會將該操作數存放在常量池,用#indexbyte表示其位置;
op指的是操作碼,通常用一個字節表示;

字節碼指令操作主要分為九大指令:

  • 加載和存儲指令:用于將數據在操作數棧和局部變量表來回傳輸;

  • 運算指令:用于將操作數棧棧頂的兩個數值進行運算,然后重新放入操作數棧頂;

  • 類型轉換指令:用于將兩個不同數值類型進行相互轉換;

  • 對象創建和訪問指令: 用于創建對象和訪問對象

  • 操作數棧管理指令:用于管理操作數棧,類似普通棧管理

  • 控制轉移指令:用于讓jvm從指定位置的指令開始執行而不是控制下一條指令位置開始執行;

  • 方法調用和返回指令:用于方法調用和方法返回;

  • 異常處理指令:對jvm拋出的異常進行處理指令;

  • 方法同步指令:用來控制不同線程對方法的同步控制;

加載和存儲指令

加載指令主要是將局部變量和常量壓入到操作數棧,具體指令有:

  • 常量壓棧指令,常量壓棧指令時根據常量所占字節大小劃分,指令如下:

    • constant:該常量字節大小為-1到5的數值,例如iconstant_0將整數0壓棧,lconstant_5將長整數5壓棧;

    • bipush:將字節值為byte類型的數值轉換為整型,然后壓棧(byte值大小為-128-127);

    • sipush:將字節值為short類型的數值轉換為整型,然后壓棧(short值為-32768-32767);

    • ldc: 根據指定索引值(需要一個字節存儲的indexbyte)從常量池取出大小在-2147483648~2147483647的常量值,如int,float,Reference型常量值;

    • ldc_w:根據指定寬索引值(需要兩個字節存儲的索引值)從常量池取出如int,float,Reference等常量值進行壓棧;

    • ldc2_w:根據指定寬索引值從常量池中取出如long,double等常量值進行壓棧;
      如下圖:

       

       

      常量壓棧.png

       

      如上圖所示,其中32767表示操作數值,在[-32768,32767]之間是不會保存到常量池的,而超過這個值則需要利用indexbyte(#30,#35)代表的索引,去常量池中查找

  • load:將局部變量指定位置(具體值或者索引)處的對象壓棧;aload_0將局部變量表0處的引用類型入棧,
    iload indexbyte將局部變量表中indexbyte表示的int類型入棧;caload從char類型數組中裝載指定項的值(先轉換為int類型值,后壓棧)

  • store :將操作數棧棧頂值彈出并保存到局部變量表中;例如:istore_3將short,byte,char,int類型保存到局部變量表3處根據類型轉換,lstore [opNum] (opNum需大于3)則將long類型保存到局部變量opNum處;dstore用來保存棧頂的double類型,fstore用來保存棧頂的float類型;

如下圖所示:

加載存儲指令.png

運算指令

運算指令有以下幾種:

  • (T)add:將棧頂T類型的兩個數值相加后入棧,T:float,int,short,long,double

  • (T)sub:將棧頂T類型的兩個數值相減后入棧,T:float,int,short,long,double

  • (T)mul:將棧頂T類型的兩個數值相乘后入棧,T:float,int,short,long,double

  • (T)div:將棧頂T類型的兩個數值相除后入棧,T:float,int,short,long,double

  • (T)rem:將棧頂T類型的兩個數值取模后入棧,T:float,int,short,long,double

  • (T)neg:將棧頂T類型的取負后入棧,T:float,int,short,long,double

  • (T)iinc [indexbyte,constantbyte]:將整數值constbyte加到indexbyte指定的int類型的局部變量中;

     

     

         

    運算指令.png

  • (T)shl:算數左移后入棧,T為非浮點類型的基本類型;

  • (T)shr:算數左移后入棧,T為非浮點類型的基本類型;

  • (T)ushl:邏輯左移后入棧,T為非浮點類型的基本類型;

  • (T)ushr:邏輯右移后入棧,T為非浮點類型的基本類型;

  • (T)and:與操作,T為非浮點類型的基本類型;

  • (T)or:或操作,T為非浮點類型的基本類型;

  • (T)xor:異或操作,T為非浮點類型的基本類型;

類型轉換指令

類型轉換指令有以下幾種:

  • (T)2(V):將T基本類型轉換成V基本類型,如果是長字節類型轉換短字節類型,則需要把高位字節截斷;如l2i:將long轉換成int則會把高4個字節截斷后剩下的四個字節轉換成int;

對象創建和訪問指令

對象創建和訪問指令通常需要兩個操作數indexbyte1和indexbyte2

  • new :創建新的對象實例;

  • checkcast:強制類型轉換;

  • instanceof:判斷是否類實例;

  • getField:獲取類實例字段值;

  • putField:給類實例字段賦值;

  • getStatic:獲取類靜態變量值;

  • putStatic:給類靜態變量賦值;

  • newarray:創建基本類型數組;

  • anewarray:創建引用類型數組;

  • arraylength:獲取一維數組長度;

操作數棧管理指令

字等于兩個字節,半個slot,16位

  • nop: 空操作;

  • pop :彈出棧頂一個字長數據;

  • pop2:彈出棧頂兩個字長的數據;

  • dup:復制棧頂一個字長的數據,同時將該數據入棧;

  • dup_x1:復制棧頂一個字長的數據,同時彈出棧頂兩個字長的數據,然后再將復制的數據入棧,再將彈出的兩個字入棧;

  • dup_x2:復制棧頂一個字長的數據,同時彈出棧頂三個字長的數據,然后再將復制的數據入棧,再將彈出的三個字入棧;

  • dup2:復制棧頂兩個字長的數據,同時將該數據入棧;

  • dup2_x1:復制棧頂兩個字長的數據,同時彈出棧頂三個字長的數據,然后再將復制的數據入棧,再將彈出的三個字入棧;

  • dup2_x2:復制棧頂兩個字長的數據,同時彈出棧頂四個字長的數據,然后再將復制的數據入棧,再將彈出的四個字入棧;

  • swap:交換棧頂兩個字長的數據,Java指令中沒有提供交換兩個字長為單位的交換指令;

控制轉移指令:

控制轉移指令分為跳轉指令和比較指令,無條件跳轉指令,表跳轉指令,異常跳轉指令;
跳轉指令:

  • ifeq:若棧頂int類型為0則跳轉;

  • ifne:若棧頂int類型不為0則跳轉;

  • iflt:若棧頂int類型小于0則跳轉;

  • ifle: 若棧頂int類型小于等于0則跳轉;

  • ifgt:若棧頂int類型大于0則跳轉;

  • ifge:若棧頂int類型大于等于0則跳轉;

  • if_icmpeq:若棧頂兩int類型相等則跳轉;

  • if_icmpne: 若棧頂兩int類型相等則跳轉;

  • if_icmplt:若棧頂int前小于后則跳轉;

  • if_icpmle:若棧頂int前小于等于后則跳轉;

  • if_icpmgt: 若棧頂int前大于后則跳轉;

  • if_icpmge: 若棧頂int前大于等于后則跳轉;

  • ifnull: 如棧頂引用為空則跳轉;

  • ifnonnull:若棧頂引用不為空則跳轉;

  • if_acmpeq:若棧頂兩引用相等則跳轉;

  • if_acmpne: 若棧頂兩引用不相等則跳轉;

比較指令:

  • (T)cmp:比較棧頂兩個T類型大小,前者大,則1入棧;相等則0入棧;后者大則-1入棧;

  • (T)cmpl:比較棧頂兩個T類型大小,前者大,則1入棧;相等則0入棧;后者大則-1入棧;有NAN存在,則-1入棧;

  • (T)cmpg:比較棧頂兩個T類型大小,前者大,則1入棧;相等則0入棧;后者大則-1入棧;有NAN存在,則-1入棧;

無條件轉移指令:

  • goto :無條件轉移到指定位置;

  • goto_w:無條件轉移到指定位置(寬索引);

表跳轉指令:

  • tableswitch:通過索引訪問跳轉表,并跳轉;

  • lookupswitch: 通過健值訪問跳轉表,并跳轉;

異常跳轉指令:

  • athrow:拋出異常;

  • jsr:跳轉到指定程序;

  • jsr_w:跳轉到指定程序(寬索引);

  • ret:返回到指定程序;

方法調用和返回指令:

  • invokerspecial:指令用于調用一些需要特殊處理的實例方法,包括實例初始化方法、私有方法和父類方法,編譯時綁定;

  • invokevirtual:指令用于調用對象的實例方法,根據對象的實際類型進行分派,運行時綁定;

  • invokestatic:調用靜態方法;

  • invokeinterface:用以調用接口方法,在運行時搜索一個實現了這個接口方法的對象,找出適合的方法進行調用;

  • invokedynamic:用于處理新的方法分派:它允許應用級別的代碼來確定執行哪一個方法調用,只有在調用要執行的時候,才會進行這種判斷,從而達到動態語言的支持,lambda方法實現就是依賴于該指令;

  • (T)return:方法退出指令,T表示返回類型;
    關于invokespecial和invokevirtual如下圖:

     

     

         

    invokespecial和invokevirtual.png

同步方法指令:

  • monitorenter: 進入并獲得對象監視器;

  • monitorexit:退出并釋放對象監視器;

以上是“java中ASM框架有什么用”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

大化| 浦江县| 吉安县| 双柏县| 南部县| 改则县| 中江县| 开原市| 子长县| 新余市| 镇坪县| 南岸区| 福安市| 云南省| 江都市| 松潘县| 武邑县| 蕲春县| 綦江县| 井研县| 永胜县| 阿克苏市| 五大连池市| 屏东县| 玉环县| 汶上县| 米脂县| 平果县| 扶风县| 富川| 宜兰县| 广元市| 通江县| 西林县| 泾阳县| 洪雅县| 舒城县| 泉州市| 平山县| 峨边| 潜江市|