用反編譯理解程序

                                     用反編譯理解程序

   以前看過很多彙編高手,在彙編領域學到一定的程度之後,在學習其他語言是,真的能學的更快,理解的更深,比如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到類試面試題目,這裏我個人認爲這只是一種分析程序的方法,不過當程序過於龐大複雜時,將不再試用。
   

 

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