Java編譯與反編譯

大雄45發表於2021-03-20
導讀 我們可以透過javac 將Java程式的原始碼編譯成Java位元組碼,即我們常說的class檔案,這是我們通常意義上理解的編譯。
基本概念

我們可以透過javac 將Java程式的原始碼編譯成Java位元組碼,即我們常說的class檔案,這是我們通常意義上理解的編譯。但是,位元組碼並不是機器語言,要想讓機器能夠執行,還需要把位元組碼翻譯成機器指令,這個過程是透過直譯器實現的,叫解釋執行。注意:大家別把編譯和解釋執行混淆了,而後面所說的後端編譯過程是JVM為提高效率做的最佳化,在不同的虛擬機器實現中,執行引擎在執行位元組碼的時候,通常會有解釋執行(透過直譯器執行)和編譯執行(透過即時編譯器產生原生程式碼執行)兩種選擇,也可能兩者兼備。所以大家可以思考下,Java到底是屬於編譯型語言還是直譯器語言呢?那為什麼java不直接編譯成可執行檔案呢,其實主要還是為了實現跨平臺。Java原始碼透過編譯成位元組碼,然後透過不同平臺的虛擬機器解釋執行,從而實現一次編譯,到處執行的跨平臺的效果。

編譯原理

Java語言的編譯期分為前端編譯和後端編譯兩個階段

前端編譯

前端編譯是指把*.java檔案轉變成*.class檔案的過程,包括詞法分析、語法分析、語義分析與中間程式碼生成。

主要有下面幾個步驟:

Java編譯與反編譯Java編譯與反編譯

後端編譯

在部分商用虛擬機器中,Java程式最初是透過直譯器進行解釋執行的,當虛擬機器發現某個方法或程式碼塊的執行特別頻繁時,就會把這些程式碼認定為熱點程式碼

為了提高熱點程式碼的執行效率,在執行時, 虛擬機器將會把這些程式碼編譯成與本地平臺相關的機器碼

完成這個任務的後端編譯器稱為即時編譯器(JIT編譯器)

反編譯
什麼是反編譯

既然Java 編譯是指將 Java 原始碼編譯成 Java 位元組碼的過程

那麼Java 反編譯簡單說就是指根據 Java 位元組碼翻譯成原始碼的過程

為什麼要有反編譯

首先這個原始碼是字元編碼,位元組碼是二進位制位元組流,並且原始碼是給人看的,位元組碼是給虛擬機器看的

因此如果想給人看,需要將位元組碼轉為原始碼。如果想給虛擬機器執行,需要將原始碼編譯成位元組碼,當我們有類檔案想看原始碼時,可以採用反編譯的方式實現

比如想了解某個Java 語法糖編譯後,再反編譯是什麼樣的;別人給你發一個 jar 包,你需要看其中某個類是怎麼寫的,等此類情況都可以考慮是用 Java 反編譯

反編譯工具
JD-GUI

GitHub :

官網:

Java編譯與反編譯Java編譯與反編譯

下載後將類檔案或者 jar 包直接拖動到介面即可

Luyten

下載地址:

Arthas

官網:

可以使用 jad 命令將 JVM 中執行的 class 的 byte code 反編譯成 java 程式碼

javap

javap是jdk自帶的一個工具,可以對程式碼反編譯,也可以檢視java編譯器生成的位元組碼

直接透過javap -help檢視其用法

用法: javap其中, 可能的選項包括: 
  -help  --help  -?        輸出此用法訊息 
  -version                 版本資訊 
  -v  -verbose             輸出附加資訊 
  -l                       輸出行號和本地變數表 
  -public                  僅顯示公共類和成員 
  -protected               顯示受保護的/公共類和成員 
  -package                 顯示程式包/受保護的/公共類 
                           和成員 (預設) 
  -p  -private             顯示所有類和成員 
  -c                       對程式碼進行反彙編 
  -s                       輸出內部型別簽名 
  -sysinfo                 顯示正在處理的類的 
                           系統資訊 (路徑, 大小, 日期, MD5 雜湊) 
  -constants               顯示最終常量 
  -classpath指定查詢使用者類檔案的位置 
  -cp指定查詢使用者類檔案的位置 
  -bootclasspath覆蓋引導類檔案的位置

基本使用:

javac Test.java 
javap -c Test.class
jclasslib

jclasslib 是一種視覺化的位元組碼檢視工具,可以直接在 IDEA 外掛安裝

安裝以後,在 IDEA 編譯原始碼後,可以選擇 View” ->“Show Bytecode With Jclasslib即可檢視位元組碼

可以直觀地看到 class 檔案包含基本資訊、常量池、介面資訊、欄位資訊、方法資訊和屬性資訊

其中方法資訊又包含行號表、區域性變數表,異常表等

要讀懂位元組碼指令涉及的知識很多,之後的文章會透過案例詳細講解class檔案結構和位元組碼指令的執行過程

推薦兩本非常經典的圖書:《深入理解 Java 虛擬機器》、《Java 虛擬機器規範》

反編譯示例

下面看一個簡單和常見的案例:

public class ForEachDemo { 
    public static void main(String[] args) { 
 
        Listdata = new ArrayList<>(); 
        data.add("a"); 
        data.add("b"); 
 
        for (String str : data) { 
            System.out.println(str); 
        } 
 
    } 
}

我們直接在 IDEA 對該類檔案進行編譯,然後再 target 目錄中尋找該類,雙擊開啟,得到下面的反編譯原始碼:

public class ForEachDemo { 
    public ForEachDemo() { 
    } 
 
    public static void main(String[] args) { 
        Listdata = new ArrayList(); 
        data.add("a"); 
        data.add("b"); 
        Iterator var2 = data.iterator(); 
 
        while(var2.hasNext()) { 
            String str = (String)var2.next(); 
            System.out.println(str); 
        } 
 
    } 
}

從上述反編譯程式碼可以清楚地看到,原始程式碼中沒有編寫構造方法時,編譯器會自動生成一個預設構造方法;foreach 迴圈來遍歷 list 時,底層透過 iterator 來實現


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2764025/,如需轉載,請註明出處,否則將追究法律責任。

相關文章