JAVA進級篇:JDK自帶的反編譯工具 javap

flags: ACC_PRIVATE flags: ACC_PUBLIC flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3 // class java/lang/StringBuilder


6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."":()V
10: ldc #5 // String hi,
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/
lang/StringBuilder;
15: aload_1
16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/
lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: return
LineNumberTable:
line 11: 0
line 12: 25
}
SourceFile: "JavapTest2.java"


默認情況下 javap 會打印所有非私有的字段和方法,如下:

javap JavapTest2
Compiled from "JavapTest2.java"
public class com.pjmike.JVM.JavapTest2 {
public com.pjmike.JVM.JavapTest2();
public void say(java.lang.String);
}

用 javap -help查看其選項:

用法: javap  
其中, 可能的選項包括:
-help --help -? 輸出此用法消息

-version 版本信息
-v -verbose 輸出附加信息
-l 輸出行號和本地變量表
-public 僅顯示公共類和成員
-protected 顯示受保護的/公共類和成員
-package 顯示程序包/受保護的/公共類
和成員 (默認)
-p -private 顯示所有類和成員
-c 對代碼進行反彙編
-s 輸出內部類型簽名
-sysinfo 顯示正在處理的類的
系統信息 (路徑, 大小, 日期, MD5 散列)
-constants 顯示最終常量
-classpath 指定查找用戶類文件的位置
-cp 指定查找用戶類文件的位置
-bootclasspath 覆蓋引導類文件的位置

從上面就可以看到 javap 選項的一些作用,在最開始的地方,我們使用了 javap -v -p JavapTest2 。加了 -p 選項後,還會打印私有的字段和方法,加上 -v 選項後,它會盡可能地打印出所有信息,如果只需要查詢相關方法對應的字節碼,可以使用 -c 代替 -v,代碼如下:

Compiled from "JavapTest2.java"
public class com.pjmike.JVM.JavapTest2 {
private java.lang.String username;
public com.pjmike.JVM.JavapTest2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public void say(java.lang.String);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."":()V
10: ldc #5 // String hi,
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/la
ng/StringBuilder;
15: aload_1
16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/la
ng/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: return
}

可以看出少了很多附加信息,讓我們更加專心的去關注方法對應的字節碼。

JAVA進級篇:JDK自帶的反編譯工具 javap


下面簡要分析下 say方法中的打印語句,裡面涉及了字符串的拼接操作:

  1. 首先是new 指令,創建類實例的指令,在Java源代碼的字符串拼接,到了編譯器在編譯階段使用 StringBuilder類進行優化
 3: new #3 // class java/lang/StringBuilder

  1. 然後 invokespecial指令,用於調用實例初始化方法,將 StringBuilder對象初始化
 7: invokespecial #4 // Method java/lang/StringBuilder."":()V

  1. ldc將”hi”字符串常量加載到操作數棧,然後invokevirtual指令用於調用對象的實例方法,這裡調用 StringBuilder的append()拼接字符串的方法
 10: ldc #5 // String hi,
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/la
ng/StringBuilder;

  1. 最後調用 StringBuilder的toString(),將拼接後的字符串輸出
 19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

以上非常簡要的分析了 字符串拼接的字節碼操作,更多關於字節碼的指令介紹,請參閱相關文檔

小結

關於 javap 以及相關字節碼知識目前還是接觸不多,這裡只是簡單玩一玩javap,更多字節碼相關的知識以及其他反編譯工具,如`jad,cfr等還需要後續進一步深入探究。



分享到:


相關文章: