現在Java反編譯工具或者外掛程式非常多,也非常好用。比如我用的比較多得jd-gui。所以我們可能很少有機會使用到Javap命令。
這裡我簡單介紹下Javap,帶各位入個門。介紹下這個命令不是使用它進行反編譯,而是查看java編譯器為我們產生 的位元組碼,通過比較位元組碼和原始碼,我們可以發現很多的問題,一個很重要的作用就是瞭解很多編譯器內部的工作機制。
下面我們通過具體的一個例子來簡單的講講這個工具的作用,你不需要很深入的使用,這個簡單的介紹和簡單的使用就可以使你受益非淺。
首先我們先寫一個非常簡單的Java源檔案:
class StringTest { public static void main(String[] args) { int i = 2; int j = 3; }}使用Javac 命令進行編譯:
javac -g StringTest.java
最終有兩個檔案:
user ~/csdn_test/session1$ls -ltotal 16-rw-r--r-- 1 user staff 417 4 7 21:54 StringTest.class-rw-r--r-- 1 user staff 99 4 7 21:53 StringTest.java
以上步驟涉及到JAVA環境變數配置,不會的自己google,或者發帖詢問。這裡使用了-g命令,意思是產生所有調試資訊。(javac -help可以查看)
下面我們分2步來看看javap的顯示結果:
1.不帶任何參數使用javap StringTest
這裡我們可以看到的資訊有,從哪個檔案(StringTest.java)編譯過來的。類裡面調用兩個方法,一個是預設的建構函式,一個是main方法。在沒有顯式聲明構造方法時,會產生一個預設構造方法。這也驗證了,為什麼一個對象,預設總是先執行建構函式,特別是在繼承的場合下,使用這個命令就可以看的很清楚了。
2.使用-c參數javap -c StringTest
帶-p參數將額外的列印位元組碼資訊。前面的和不帶參數的輸出一樣,後面的顯示了方法的具體的位元組碼,從這個輸出裡面我們又可以瞭解更多的內容。
首先是編譯器產生的的預設構造方法的內容為調用父類的構造方法super(), main()方法的位元組碼資訊的內容這裡簡單解釋下:
Code: 0: iconst_2 //把2放到棧頂 1: istore_1 //把棧頂的值放到局部變數1中,即i中 2: iconst_3 //把3放到棧頂 3: istore_2 //把棧頂的值放到局部變數1中,即j中 4: return
所以再根據開始的java源碼對照,對於 int i = 2;首先它會在棧中建立一個變數為i的引用,然後尋找有沒有字面值為2的地址,沒找到,就開闢一個存放2這個字面值的地址,然後將i指向2的地址。j也是類似的。
延伸學習:
1、如果將main中的變數換成String 類型的,然後看看javap的結果。
比如:
String a = "a";
String b = "b";
String ab = "ab";
String ab1 = a + b;
String ab2 = "a" + "b"
2、使用更多的參數分析其結果,如javap -l xxx javap -p xxx(提示 -p會顯示private相關的)
這幾個參數幾乎就可以構成javap的最常使用的集合,最常用的應該還是-c選項,因為可以列印位元組碼的資訊,關於這些位元組碼的詳細涵義在Java 虛擬機器規範中定義,感興趣的可以自己去找找相關資料。