亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

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

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

Java中怎么調用字節碼

發布時間:2021-06-30 17:45:11 來源:億速云 閱讀:230 作者:Leah 欄目:云計算

本篇文章為大家展示了Java中怎么調用字節碼,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

實例源碼

實例共兩個java文件,一個是接口另一個是類,先看接口源碼,很簡單只有一個方法聲明:

package com.bolingcavalry;

public interface Action {
    void doAction();
}

接下來的類實現了這個接口,而且還有自己的共有、私有、靜態方法:

package com.bolingcavalry;

public class Test001 implements Action{
    private int add(int a, int b){
        return a+b;
    }

    public String getValue(int a, int b){
        return String.valueOf(add(a,b));
    }

    public static void output(String str){
        System.out.println(str);
    }

    @Override
    public void doAction() {
        System.out.println("123");
    }

    public static void main(String[] args){
        Test001 t = new Test001();
        Action a = t;
        String str = t.getValue(1,2);
        t.output(str);
        t.doAction();
        a.doAction();
    }
	
	public void createThread(){
        Runnable r = () -> System.out.println("123");
    }
}

小結一下,Test001的代碼中主要的方法如下:

  1. 一個私有方法add;

  2. 一個公有方法getValue,里面調用了add方法;

  3. 一個靜態方法output;

  4. 實現接口定義的doAction;

  5. 一個公有方法,里面使用了lambda表達式;

  6. main方法中,創建對象,調用getValue,output,doAction;

接下來我們通過javac命令或者ide工具得到Action.class和Test001.class文件,如果是用Intellij IDEA,可以先把Test001運行一遍,然后在工程目錄下找到out文件夾,打開后里面是production文件夾,再進去就能找到對應的package和class文件了,如下圖:

Java中怎么調用字節碼

打開命令行,在Test001.class目錄下執行<font color="blue">javap -c Test001.class </font>,就可以對class文件進行反匯編,得到結果如下:

Compiled from "Test001.java"
public class com.bolingcavalry.Test001 implements com.bolingcavalry.Action {
  public com.bolingcavalry.Test001();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public java.lang.String getValue(int, int);
    Code:
       0: aload_0
       1: iload_1
       2: iload_2
       3: invokespecial #2                  // Method add:(II)I
       6: invokestatic  #3                  // Method java/lang/String.valueOf:(I)Ljava/lang/String;
       9: areturn

  public static void output(java.lang.String);
    Code:
       0: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_0
       4: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       7: return

  public void doAction();
    Code:
       0: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #6                  // String 123
       5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class com/bolingcavalry/Test001
       3: dup
       4: invokespecial #8                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: astore_2
      10: aload_1
      11: iconst_1
      12: iconst_2
      13: invokevirtual #9                  // Method getValue:(II)Ljava/lang/String;
      16: astore_3
      17: aload_1
      18: pop
      19: aload_3
      20: invokestatic  #10                 // Method output:(Ljava/lang/String;)V
      23: aload_1
      24: invokevirtual #11                 // Method doAction:()V
      27: aload_2
      28: invokeinterface #12,  1           // InterfaceMethod com/bolingcavalry/Action.doAction:()V
      33: return

public void createThread();
    Code:
       0: invokedynamic #13,  0             // InvokeDynamic #0:run:()Ljava/lang/Runnable;
       5: astore_1
       6: return

}

現在我們可以對比反匯編結果來學習字節碼的用法了:

invokespecial:調用私有實例方法

getValue()方法中調用了私有實例方法add(int a, int b),反編譯結果如下所示,注意編號為3的那一行:

public java.lang.String getValue(int, int);
    Code:
       0: aload_0
       1: iload_1
       2: iload_2
       3: invokespecial #2                  // Method add:(II)I
       6: invokestatic  #3                  // Method java/lang/String.valueOf:(I)Ljava/lang/String;
       9: areturn

可見私有實例方法的調用是通過invokespecial指令來實現的;

invokestatic:調用靜態方法

getValue()方法中,調用了靜態方法String.valueOf(),反編譯結果如下所示,注意編號為6的那一行:

public java.lang.String getValue(int, int);
    Code:
       0: aload_0
       1: iload_1
       2: iload_2
       3: invokespecial #2                  // Method add:(II)I
       6: invokestatic  #3                  // Method java/lang/String.valueOf:(I)Ljava/lang/String;
       9: areturn

可見靜態方法的調用是通過invokestatic指令來實現的;

invokevirtual:調用實例方法

在main()方法中,調用了t.getValue(1,2)方法,反編譯結果如下所示,注意編號為13的那一行:

public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class com/bolingcavalry/Test001
       3: dup
       4: invokespecial #8                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: astore_2
      10: aload_1
      11: iconst_1
      12: iconst_2
      13: invokevirtual #9                  // Method getValue:(II)Ljava/lang/String;
      16: astore_3
      17: aload_1
      18: pop
      19: aload_3
      20: invokestatic  #10                 // Method output:(Ljava/lang/String;)V
      23: aload_1
      24: invokevirtual #11                 // Method doAction:()V
      27: aload_2
      28: invokeinterface #12,  1           // InterfaceMethod com/bolingcavalry/Action.doAction:()V
      33: return
}

可見調用一個實例的方法的時候,通過invokevirtual指令來實現的;

invokeinterface:調用接口方法

在main()方法中,我們聲明了接口Action a,然后調用了a.doAction(),反編譯結果如下所示,注意編號為28的那一行:

public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class com/bolingcavalry/Test001
       3: dup
       4: invokespecial #8                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: astore_2
      10: aload_1
      11: iconst_1
      12: iconst_2
      13: invokevirtual #9                  // Method getValue:(II)Ljava/lang/String;
      16: astore_3
      17: aload_1
      18: pop
      19: aload_3
      20: invokestatic  #10                 // Method output:(Ljava/lang/String;)V
      23: aload_1
      24: invokevirtual #11                 // Method doAction:()V
      27: aload_2
      28: invokeinterface #12,  1           // InterfaceMethod com/bolingcavalry/Action.doAction:()V
      33: return
}

可見調用一個接口的方法是通過invokeinterface指令來實現的; 其實t.doAction()和a.doAction()最終都是調用Test001的實例的doAction,但是t的聲明是類,a的聲明是接口,所以兩者的調用指令是不同的;

invokedynamic:調用動態方法

在main()方法中,我們聲明了一個lambda() -> System.out.println("123"),反編譯的結果如下:

 0: invokedynamic #13,  0             // InvokeDynamic #0:run:()Ljava/lang/Runnable;
       5: astore_1
       6: return

可見lambda表達式對應的實際上是一個invokedynamic調用,具體的調用內容,可以用Bytecode viewer這個工具來打開Test001.class再研究,由于反編譯后得到invokedynamic的操作數是#13,我們先去常量池看看13對應的內容:

Java中怎么調用字節碼

是個Name and type和Bootstrap method,再細看Bootstrap method的操作數,如下圖:

Java中怎么調用字節碼

是個MethodHandler的引用,指向了用戶實現的lambda方法;

上述內容就是Java中怎么調用字節碼,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

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

AI

扶风县| 凉城县| 黄龙县| 莱阳市| 沙河市| 太仆寺旗| 波密县| 平利县| 元谋县| 新宁县| 成都市| 南阳市| 调兵山市| 石泉县| 于都县| 武汉市| 屯留县| 慈利县| 油尖旺区| 大埔区| 武川县| 资兴市| 扎囊县| 永安市| 汝南县| 永顺县| 盐边县| 乐陵市| 大冶市| 余姚市| 万全县| 岗巴县| 文昌市| 东台市| 新绛县| 且末县| 怀化市| 开原市| 庆城县| 连云港市| 安泽县|