Java—Jvm字節碼實例解析

本文不對字節碼中的每一個指令進行解析,只對幾個實例進行解析,以此來了解java文件編譯後生產的class字節碼。實例中所有所有代碼均可直接使用,建議自己重新實驗一下。JVM字節碼在通常開發情況下沒有用處,但是是一種無侵入監控方法(動態字節碼技術)、匪夷所思的BUG調試的重要技術手段。

一、環境

(1)JDK1.7

(2)javac Test.java 生產Test.class

(3)javap -c Test.class > test.txt 輸出JVM字節碼


二、字節碼實例

字符串

StringAppend類爲例

源碼如下:

package com.owl.zookeeper.string;
public class StringAppend {
    public static void main(String[] args) {
        String a = "1";
        String b = "2" + a + "3";
        System.out.println(b);
    }
}
字節碼如下:
 Compiled from "StringAppend.java"
 public class com.owl.zookeeper.string.StringAppend {
 public com.owl.zookeeper.string.StringAppend();
 Code:
 0: aload_0  //將this入棧
 1: invokespecial #1                  // Method java/lang/Object."<init>":()V //調用Object的構造方法
 4: return                            //返回void

 public static void main(java.lang.String[]);
 Code:
 0: ldc           #2                  // String 1  解釋:LDC cst:將常量池偏移量爲cst的值入棧,譬如LDC #12,在操作棧中會佔用1個字長
 2: astore_1                          解釋:將棧頂的String 1賦值給第一個變量a
 3: new           #3                  // class java/lang/StringBuilder 解釋:創建對象,並將該對象入棧頂
 6: dup                               解釋:複製棧頂數據StringBuilder。因爲方法調用會彈出參數(這裏是Object對象),因此需要上面的dup指令,保證在調用構造函數之後棧頂上還是 Object對象的引用,很多種情況下dup指令都是爲這個目的而存在的。
 7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V 解釋:調用StringBuilder構造方法
 10: ldc           #5                  // String 2 解釋:將String 2壓入棧頂
 12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 解釋:棧頂2出棧,作爲方法入參,調用java/lang/StringBuilder.append()方法
 15: aload_1                           解釋:將變量a的1入棧
 16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 解釋:將變量a的1出棧,作爲方法入參,調用java/lang/StringBuilder.append()方法
 19: ldc           #7                  // String 3 解釋:將常量池中的字符串3入棧
 21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 解釋:將字符串3出棧,作爲方法入參,調用java/lang/StringBuilder.append()方法
 24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 解釋:調用StringBuilder.toString
 27: astore_2                          解釋:將返回值保存在變量b
 28: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream; 解釋:獲得靜態變量,System.out
 31: aload_2                           解釋:變量2入棧
 32: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 解釋:變量2出棧,作爲println的方法
 35: return                            解釋:返回


循環

StringForAppend類爲例

源碼如下:

public class StringForAppend {
    public static void main(String[] args) {
        String a = "";
        for(int i = 0; i < 3; i ++) {
            a += "1";
        }
        System.out.println(a);
    }
}

字節碼如下:

 Compiled from "StringForAppend.java"
 public class com.owl.zookeeper.string.StringForAppend {
 public com.owl.zookeeper.string.StringForAppend();
 Code:
 0: aload_0
 1: invokespecial #1                  // Method java/lang/Object."<init>":()V
 4: return

 public static void main(java.lang.String[]);
 Code:
 0: ldc           #2                  // String 解釋:將常量空字符串入棧
 2: astore_1                          解釋:將空字符串賦值給a
 3: iconst_0                          解釋:將常量integer 0入棧
 4: istore_2                          解釋:出棧0,賦值給變量0
 5: iload_2                           解釋:將變量i=0,入棧
 6: iconst_3                          解釋:將integer 3入棧
 7: if_icmpge     36                  解釋:比較棧頂兩個元素,如果相等則跳轉到36
 10: new           #3                  // class java/lang/StringBuilder 創建StringBuilder,併入棧
 13: dup                               解釋:複製棧頂
 14: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V 解釋:出棧調用StringBuilder的構造方法
 17: aload_1                           解釋:入棧空字符串
 18: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 出棧空字符串,出棧StringBuilder,執行append方法
 21: ldc           #6                  // String 1 解釋:常量1入棧
 23: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 出棧字符串1,調用append方法
 26: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 出棧StringBuilder,調用append方法,將結果入棧
 29: astore_1                          解釋:出棧""+1,保存到變量a
 30: iinc          2, 1                解釋:將變量i,遞增1
 33: goto          5                   解釋:跳轉到步驟5
 36: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;解釋:獲得對象PrintStream,入棧
 39: aload_1                           解釋:入棧變量a
 40: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V 出棧變量a,出棧PrintStream,調用println方法
 43: return                            解釋:返回


判斷

StringIf類爲例

源碼如下:

public class StringIf {
    public static void main(String[] args) {
        String a = "123";
        if("123" == (a)) {
            System.out.println(a);
        }else {
            String b = a + "!";
            System.out.println(b);
        }
    }
}

字節碼如下:

 Compiled from "StringIf.java"
 public class com.owl.zookeeper.string.StringIf {
 public com.owl.zookeeper.string.StringIf();
 Code:
 0: aload_0
 1: invokespecial #1                  // Method java/lang/Object."<init>":()V
 4: return

 public static void main(java.lang.String[]);
 Code:
 0: ldc           #2                  // String 123 解釋:將常量123入棧
 2: astore_1                          解釋:出棧123,賦值給變量a
 3: ldc           #2                  // String 123  解釋:將常量123入棧
 5: aload_1                           解釋:入棧123
 6: if_acmpne     19                  解釋:比較棧頂兩個元素,如果符合跳轉到指定位置
 9: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;解釋:獲得System.out對象,入棧
 12: aload_1                          解釋:入棧123
 13: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V 解釋:出棧參數,出棧調用方法對象
 16: goto          46                  解釋:跳轉到結束
 19: new           #5                  // class java/lang/StringBuilder 創建一個 解釋:創建一個StringBuilder對象,併入棧
 22: dup                               解釋:複製棧頂數據,併入棧
 23: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V 解釋:出棧並調用構造方法
 26: aload_1                           解釋:入棧123
 27: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;解釋:出棧123,出棧StringBUilder,調用方法,入棧StirngBuilder
 30: ldc           #8                  // String ! 解釋:入棧常量!
 32: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;解釋:出棧!,出棧StringBuilder,調用append(!),入棧StirngBuilder
 35: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 解釋:出棧StringBuilder,調用toString()
 38: astore_2                          解釋:出棧123!,賦值給變量b
 39: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream; 解釋:獲得PrintStream,併入棧
 42: aload_2                           解釋:入棧123!
 43: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V  出棧2個棧位,調用println
 46: return                            解釋:返回


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章