溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java中怎么調(diào)用字節(jié)碼

發(fā)布時(shí)間:2021-06-30 17:45:11 來(lái)源:億速云 閱讀:229 作者:Leah 欄目:云計(jì)算

本篇文章為大家展示了Java中怎么調(diào)用字節(jié)碼,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。

實(shí)例源碼

實(shí)例共兩個(gè)java文件,一個(gè)是接口另一個(gè)是類(lèi),先看接口源碼,很簡(jiǎn)單只有一個(gè)方法聲明:

package com.bolingcavalry;

public interface Action {
    void doAction();
}

接下來(lái)的類(lèi)實(shí)現(xiàn)了這個(gè)接口,而且還有自己的共有、私有、靜態(tài)方法:

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");
    }
}

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

  1. 一個(gè)私有方法add;

  2. 一個(gè)公有方法getValue,里面調(diào)用了add方法;

  3. 一個(gè)靜態(tài)方法output;

  4. 實(shí)現(xiàn)接口定義的doAction;

  5. 一個(gè)公有方法,里面使用了lambda表達(dá)式;

  6. main方法中,創(chuàng)建對(duì)象,調(diào)用getValue,output,doAction;

接下來(lái)我們通過(guò)javac命令或者ide工具得到Action.class和Test001.class文件,如果是用Intellij IDEA,可以先把Test001運(yùn)行一遍,然后在工程目錄下找到out文件夾,打開(kāi)后里面是production文件夾,再進(jìn)去就能找到對(duì)應(yīng)的package和class文件了,如下圖:

Java中怎么調(diào)用字節(jié)碼

打開(kāi)命令行,在Test001.class目錄下執(zhí)行<font color="blue">javap -c Test001.class </font>,就可以對(duì)class文件進(jìn)行反匯編,得到結(jié)果如下:

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

}

現(xiàn)在我們可以對(duì)比反匯編結(jié)果來(lái)學(xué)習(xí)字節(jié)碼的用法了:

invokespecial:調(diào)用私有實(shí)例方法

getValue()方法中調(diào)用了私有實(shí)例方法add(int a, int b),反編譯結(jié)果如下所示,注意編號(hào)為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

可見(jiàn)私有實(shí)例方法的調(diào)用是通過(guò)invokespecial指令來(lái)實(shí)現(xiàn)的;

invokestatic:調(diào)用靜態(tài)方法

getValue()方法中,調(diào)用了靜態(tài)方法String.valueOf(),反編譯結(jié)果如下所示,注意編號(hào)為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

可見(jiàn)靜態(tài)方法的調(diào)用是通過(guò)invokestatic指令來(lái)實(shí)現(xiàn)的;

invokevirtual:調(diào)用實(shí)例方法

在main()方法中,調(diào)用了t.getValue(1,2)方法,反編譯結(jié)果如下所示,注意編號(hào)為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
}

可見(jiàn)調(diào)用一個(gè)實(shí)例的方法的時(shí)候,通過(guò)invokevirtual指令來(lái)實(shí)現(xiàn)的;

invokeinterface:調(diào)用接口方法

在main()方法中,我們聲明了接口Action a,然后調(diào)用了a.doAction(),反編譯結(jié)果如下所示,注意編號(hào)為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
}

可見(jiàn)調(diào)用一個(gè)接口的方法是通過(guò)invokeinterface指令來(lái)實(shí)現(xiàn)的; 其實(shí)t.doAction()和a.doAction()最終都是調(diào)用Test001的實(shí)例的doAction,但是t的聲明是類(lèi),a的聲明是接口,所以兩者的調(diào)用指令是不同的;

invokedynamic:調(diào)用動(dòng)態(tài)方法

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

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

可見(jiàn)lambda表達(dá)式對(duì)應(yīng)的實(shí)際上是一個(gè)invokedynamic調(diào)用,具體的調(diào)用內(nèi)容,可以用Bytecode viewer這個(gè)工具來(lái)打開(kāi)Test001.class再研究,由于反編譯后得到invokedynamic的操作數(shù)是#13,我們先去常量池看看13對(duì)應(yīng)的內(nèi)容:

Java中怎么調(diào)用字節(jié)碼

是個(gè)Name and type和Bootstrap method,再細(xì)看Bootstrap method的操作數(shù),如下圖:

Java中怎么調(diào)用字節(jié)碼

是個(gè)MethodHandler的引用,指向了用戶實(shí)現(xiàn)的lambda方法;

上述內(nèi)容就是Java中怎么調(diào)用字節(jié)碼,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI