查看java編譯過程的JAD工具

今天帶來一個好玩的工具——JAD,他是幹什麼的呢,這個工具可以把java的類文件反編譯成java的源代碼,用過android反編譯的肯定玩過JD_GUI這個工具,他可以查看.jar文件裏面的類信息,雖然JAD沒有JD_GUI那麼的強勢(JAD看不了jar文件),但是,對於學java的一些執行過程來說,還是很有幫助的,關鍵是十分的有趣。

使用必備工具:JAD.exe下載鏈接,我們下載下來最好放在配置了java環境的jdk的bin目錄下面,這樣可以隨意jad的去玩,再來一個JAD的命令使用大全

ok,準備完畢,接下來帶來一個好玩的東西,也是無意之中發現的,在jdk1.7之後,switch語句已經支持使用String去作爲判斷類型了,下面就針對這個例子玩一下。

java源代碼

class A{
 public static void main(String args[]){
      String a="hello";
      String b="";
      switch(a){
         case "word":
           b="word";
           break;
         case "hello":
           b="hello";
           break;
      }
   System.out.println(b);
  }
}

java代碼沒什麼,接下來我們編譯一下這個類文件,會生成A.class文件

javac A.java

然後我們輸入jad的反編譯命令,下面這句話的意思是,-P是輸出到哪裏,A.class是被反編譯的類文件,>是輸出到哪裏,B.java指定輸出的文件

jad -p A.class>B.java

然後我們打開B.java查看一下這個被反編譯後的代碼

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   A.java
import java.io.PrintStream;
class A
{
    A(){ }
    public static void main(String args[])
    {
        String s = "hello";
        String s1 = "";
        String s2 = s;
        byte byte0 = -1;
        switch(s2.hashCode())
        {
        case 3655434: 
            if(s2.equals("word"))
                byte0 = 0;
            break;
        case 99162322: 
            if(s2.equals("hello"))
                byte0 = 1;
            break;
        }
        switch(byte0)
        {
        case 0: // '\0'
            s1 = "word";
            break;

        case 1: // '\001'
            s1 = "hello";
            break;
        }
        System.out.println(s1);
    }
}

再來一張對比的照片

這裏寫圖片描述

這個代碼很有特點,也讓我們知道了java是怎麼去處理switch的字符串,接下來我們分析分析。

首先我們可以看到最上部分的註釋信息,這個信息似乎是去不掉的,很有特點,哈哈。

上面還有一個import的導包,我們明明在java代碼中是沒有導過包的,怎麼這裏出現這個包呢,要知道,System.out.println這個語句中的println,是io操作的,雖然我們java文件沒有導包,因爲我們使用的是默認的lang包,所以,明白的吧。

接下來繼續,類的初始化會觸發默認的構造函數,雖然我們在java代碼中沒有寫,但是,反編譯的時候,我們卻清晰可見,構造方法A被調用過了。

接下來看main方法,這個地方是勾起我最有趣的地方,在jdk1.7之前,switch是不支持String類型的判斷的,但是在1.7後開始支持了,後來在想,他是怎麼支持字符串的呢,在編譯java代碼的時候,jvm只支持8種基本類型,沒有String的身影啊,然後通過jad編譯之後,發現了這個好玩的地方。
我們看switch判斷部分,他將字符串進行了hash計算,最終,還是通過數值進行的判斷,我們知道,同一個字符串的Hash值肯定是相同的,但是呢,反過來一樣嗎?那當然肯定不一樣,那是小概率事件,不過,通過這個編譯的源碼可以看出,還是對這些小概率做了處理,那就是在case語句中,進行equals的判斷,如果出現小概率事件了,不要緊,我們再判斷一下值是否一樣,如果這兩個都滿足了,我們就給個flag值,也就是byte0。
這編譯代碼真好玩,又來一個switch繼續判斷,哈哈,還是挺奇妙的,代碼不難,大家自己看看,反正,我覺得是非常的有趣。

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