1.javap指令是什麼?
可以通過javap指令看到java程式在執行過程中,每一句代碼真正地做了什麼,包括cpu的指令和jvm具體做了什麼,可以在發生一些錯誤或者奇怪的事情的時候,知道為什麼會這樣。
javap是jdk自帶的反解析工具。作用是根據class位元組碼檔案,反解析出目前類對應的code區(彙編指令)、本地變量表、異常表和代碼行偏移量映射表、常量池等等資訊。
這些資訊當中,有些資訊,比如本地變量表、指令和代碼偏移映射表,常量池中的方法的參數名稱等,需要在使用javac編譯成class檔案時,指定參數才能輸出。使用javac -g xx.java就可以生成所有相關的資訊了。
通過局部變量表,我們可以檢視局部變量的作用域範圍,所在槽位等資訊,甚至可以看到槽位複用等資訊。
javap的用法格式
javap
其中classes就是你要反編譯的class檔案。不需要帶字尾.class。
指令行中直接輸入javap或者javap -help可以看到javap的options:
用法: javap <options> <classes>
其中, 可能的選項包括:
-help --help -? 輸出此用法消息
-version 版本資訊
-v -verbose 輸出附加資訊
-l 輸出行号和本地變量表
-public 僅顯示公共類和成員
-protected 顯示受保護的/公共類和成員
-package 顯示程式包/受保護的/公共類
和成員 (預設)
-p -private 顯示所有類和成員
-c 對代碼進行反彙編
-s 輸出内部類型簽名
-sysinfo 顯示正在處理的類的
系統資訊 (路徑, 大小, 日期, MD5 散列)
-constants 顯示最終常量
--module <子產品>, -m <子產品> 指定包含要反彙編的類的子產品
--module-path <路徑> 指定查找應用程式子產品的位置
--system <jdk> 指定查找系統子產品的位置
--class-path <路徑> 指定查找使用者類檔案的位置
-classpath <路徑> 指定查找使用者類檔案的位置
-cp <路徑> 指定查找使用者類檔案的位置
-bootclasspath <路徑> 覆寫引導類檔案的位置
一般常用的是-v -l -c三個選項
javap -v classxx,不僅會輸出行号、本地變量表資訊、反編譯彙編代碼,還會輸出目前類用到的常量池等資訊。
javap -l 會輸出行号和本地變量表資訊
javap -c 會對目前class位元組碼進行反編譯生成彙編代碼。
也可以通過jclasslib工具來看到上面的資訊
2.一些測試
主要介紹code區(彙編指令)、局部變量表和代碼偏移映射三個部分
建立一個TestDate.java檔案
import java.util.Date;
public class TestDate {
private int count = 0;
public static void main(String[] args) {
TestDate testDate = new TestDate();
testDate.test1();
}
public void test1(){
Date date = new Date();
String name1 = "wangerbei";
test2(date,name1);
System.out.println(date+name1);
}
public void test2(Date dateP,String name2){
dateP = null;
name2 = "zhangsan";
}
public void test3(){
count++;
}
public void test4(){
int a = 0;
{
int b = 0;
b = a+1;
}
int c = a+1;
}
}
使用指令:javac - g TestDate.java,生成一個TestDate.class檔案
再使用javap指令對位元組碼檔案進行反彙編,使用指令javap -c -l TestDate
此時不需要加字尾.class
Compiled from "TestDate.java"
public class TestDate {
//預設的構造方法,在構造方法執行時完成一些初始化操作,包括一些成員變量的初始化指派等
public TestDate();
Code:
0: aload_0 //從本地變量表中加載索引為0的變量的值,也就是this的引用,壓入棧
1: invokespecial #1 // 調用方法 java/lang/Object."<init>":()V 完成this對象的初始化
4: aload_0 //
5: iconst_0
6: putfield #2 // Field count:I
9: return
LineNumberTable:
line 2: 0
line 4: 4
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this LTestDate;
public static void main(java.lang.String[]);
Code:
0: new #3 // class TestDate
3: dup
4: invokespecial #4 // Method "<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #5 // Method test1:()V
12: return
LineNumberTable:
line 7: 0
line 8: 8
line 9: 12
LocalVariableTable:
Start Length Slot Name Signature
0 13 0 args [Ljava/lang/String;
8 5 1 testDate LTestDate;
public void test1();
Code:
0: new #6 // class java/util/Date
3: dup
4: invokespecial #7 // Method java/util/Date."<init>":()V
7: astore_1
8: ldc #8 // String wangerbei
10: astore_2
11: aload_0
12: aload_1
13: aload_2
14: invokevirtual #9 // Method test2:(Ljava/util/Date;Ljava/lang/String;)V
17: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
20: aload_1
21: aload_2
22: invokedynamic #11, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/util/Date;Ljava/lang/String;)Ljava/lang/String;
27: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: return
LineNumberTable:
line 12: 0
line 13: 8
line 14: 11
line 15: 17
line 16: 30
LocalVariableTable:
Start Length Slot Name Signature
0 31 0 this LTestDate;
8 23 1 date Ljava/util/Date;
11 20 2 name1 Ljava/lang/String;
public void test2(java.util.Date, java.lang.String);
Code:
0: aconst_null
1: astore_1
2: ldc #13 // String zhangsan
4: astore_2
5: return
LineNumberTable:
line 19: 0
line 20: 2
line 21: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this LTestDate;
0 6 1 dateP Ljava/util/Date;
0 6 2 name2 Ljava/lang/String;
public void test3();
Code:
0: aload_0
1: dup
2: getfield #2 // Field count:I
5: iconst_1
6: iadd
7: putfield #2 // Field count:I
10: return
LineNumberTable:
line 24: 0
line 25: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this LTestDate;
public void test4();
Code:
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_1
5: iconst_1
6: iadd
7: istore_2
8: iload_1
9: iconst_1
10: iadd
11: istore_2
12: return
LineNumberTable:
line 28: 0
line 30: 2
line 31: 4
line 33: 8
line 34: 12
LocalVariableTable:
Start Length Slot Name Signature
4 4 2 b I
0 13 0 this LTestDate;
2 11 1 a I
12 1 2 c I
}
參考資料:https://www.jianshu.com/p/6a8997560b05