用反編譯理解程序
以前看過很多彙編高手,在彙編領域學到一定的程度之後,在學習其他語言是,真的能學的更快,理解的更深,比如c, java ,c++ 等等。。。。
我這裏也有一個用java自帶命令幫助我們理解程序的方法。
下面這段代碼是關於(zt)變態java面試題中的第一個,問你下面這段代碼#mmm處的運行結果?
我補充了一下,順便用運行在虛擬機上的代碼簡單的說明下。
public class TestExamMethod {
public static void main(String[] args){
TestExamMethod instance = new TestExamMethod();
instance.test1();
}
public void test1(){
int x=4;
System.out.println("value is " +((x>4)?99.9:9)); //#mmm
System.out.println("value is " +((x>4)?99:9)); //#nnn
}
}
-------------------------------------------------------------------------------------------------------------
E:/wytest>javap -c TestExamMethod
Compiled from "TestExamMethod.java"
public class test.thinkinjava.TestExamMethod extends java.lang.Object{
public test.thinkinjava.TestExamMethod();
Code:
0: aload_0
1: invokespecial #9; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2; //class test/thinkinjava/TestExamMethod
3: dup
4: invokespecial #16; //Method "<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #19; //Method test1:()V
12: return
public void test1();
Code:
0: iconst_4
1: istore_1
2: getstatic #28; //Field java/lang/System.out:Ljava/io/PrintStream;
5: new #30; //class java/lang/StringBuffer
8: dup
9: ldc #32; //String value is
11: invokespecial #35; //Method java/lang/StringBuffer."<init>":(Ljava/lan
g/String;)V
14: iload_1
15: iconst_4
16: if_icmple 25
19: ldc2_w #36; //double 99.9d
22: goto 28
25: ldc2_w #38; //double 9.0d
28: invokevirtual #43; //Method java/lang/StringBuffer.append:(D)Ljava/lan
g/StringBuffer;
31: invokevirtual #47; //Method java/lang/StringBuffer.toString:()Ljava/la
ng/String;
34: invokevirtual #52; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
37: getstatic #28; //Field java/lang/System.out:Ljava/io/PrintStream;
40: new #30; //class java/lang/StringBuffer
43: dup
44: ldc #32; //String value is
46: invokespecial #35; //Method java/lang/StringBuffer."<init>":(Ljava/lan
g/String;)V
49: iload_1
50: iconst_4
51: if_icmple 59
54: bipush 99
56: goto 61
59: bipush 9
61: invokevirtual #55; //Method java/lang/StringBuffer.append:(I)Ljava/lan
g/StringBuffer;
64: invokevirtual #47; //Method java/lang/StringBuffer.toString:()Ljava/la
ng/String;
67: invokevirtual #52; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
70: return
}
-----------------------------------------------------------------------------------
主要看test1()方法,先說明下概念:
1、bipush :將8位帶符號的整數入棧,但要先將8位擴展爲int需要的位數。
2、if_icmple :你可以簡單的先理解爲if()條件語句。。。
3、iconst_4 :將int類型常量4壓入棧
4、iload_1 :從局部變量1中裝載int
5、ldc2_w :把常量池中的long/double類型的項壓入棧。
其他具體內容你可以查看 《深入Java虛擬機》查找。
藉助反編譯代碼說明源代碼運行結果:
System.out.println("value is " +((x>4)?99:9)); //#nnn
他在運行時,99 ---> int 類型,先壓入棧 [ bipush 99 ]
然後 9 ----> int 類型 在壓入棧 [bipush 9]
當然取出來運行的結果自然是: value is 9
System.out.println("value is " +((x>4)?99.9:9)); //#mmm
他在運行時,99.9 ---> double 類型,先壓入棧 [ dc2_w #36; //double 99.9d ]
然後 9----> int類型, 但虛擬機這時將?前後的類型轉型,規則和我們寫 int + double 時一樣。
所以這裏 9 ---> 9.0 ---> double類型壓入棧,[ ldc2_w #38; //double 9.0d ]
當然取出來運行的結果自然是: value is 9.0
同樣,如果我們這是要運行 System.out.println("value is " +((x==4)?99:9.0));
結果應該是99.0 規則同樣和 int + double 一樣。
在java實現論壇上有10到類試面試題目,這裏我個人認爲這只是一種分析程序的方法,不過當程序過於龐大複雜時,將不再試用。