Java反編譯工具


編譯和反編譯

編程語言分成高級語言和低級語言。低級語言如機器語言、匯編語言。這類語言直接用計算機指令編寫命令,不需要編譯。這些語言機器能看到懂,但是程序員讀起來很費勁。而我們平時經常用的語言C、Java、Python屬於高級語言,這些語言程序員能看的懂。而機器是看不懂的。

簡單的總結為:高級語言就是程序員認識的語言,而低級語言是機器認識的語言。而把高級語言轉成低級語言這個過程就是編譯,而反編譯就是把低級語言轉成高級語言。
有了反編譯,我們就可以看懂Java編譯器生成的字節碼,比如Synchronized的實現原理(監聽器monitor)、枚舉、語法糖、泛型,這些都需要用到反編譯工具。

javap

javap是jdk自帶的反編譯命令,可以對代碼進行反編譯,但是反編譯的並不是java文件。

使用格式

javap <options> <classes>

常用: javap -c 類名

-help  --help  -?        輸出此用法消息
-version                 版本信息
-v  -verbose             輸出附加信息
-l                       輸出行號和本地變量表
-public                  僅顯示公共類和成員
-protected               顯示受保護的/公共類和成員
-package                 顯示程序包/受保護的/公共類和成員 (默認)
-p  -private             顯示所有類和成員
-c                       對代碼進行反匯編
-s                       輸出內部類型簽名
-sysinfo                 顯示正在處理的類的系統信息 (路徑, 大小, 日期, MD5 散列)
-constants               顯示最終常量
-classpath <path>        指定查找用戶類文件的位置
-cp <path>               指定查找用戶類文件的位置
-bootclasspath <path>    覆蓋引導類文件的位置

下面寫一段synchronized代碼:

public class SynchronizedTest {

	private int count = 0;

	public  void addOne() {
		synchronized (SynchronizedTest.class) {
			count++;
		}
	}
}

執行編譯和反編譯命令

javac SynchronizedTest .java
javap -c SynchronizedTest.class

直接用記事本打開SynchronizedTest.class文件是一堆亂碼文件,用sublime打開是一串數字

cafe babe 0000 0034 0017 0a00 0400 1209
0003 0013 0700 1407 0015 0100 0563 6f75
6e74 0100 0149 0100 063c 696e 6974 3e01
0003 2829 5601 0004 436f 6465 0100 0f4c
696e 654e 756d 6265 7254 6162 6c65 0100
0661 6464 4f6e 6501 000d 5374 6163 6b4d
6170 5461 626c 6507 0014 0700 1507 0016

反編譯后的代碼:

public class com.SynchronizedTest {
  public com.SynchronizedTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_0
       6: putfield      #2                  // Field count:I
       9: return

  public void addOne();
    Code:
       0: ldc           #3                  // class com/yyw/oil/web/admin/controller/purchase/SynchronizedTest
       2: dup
       3: astore_1
       4: monitorenter
       5: aload_0
       6: dup
       7: getfield      #2                  // Field count:I
      10: iconst_1
      11: iadd
      12: putfield      #2                  // Field count:I
      15: aload_1
      16: monitorexit
      17: goto          25
      20: astore_2
      21: aload_1
      22: monitorexit
      23: aload_2
      24: athrow
      25: return
    Exception table:
       from    to  target type
           5    17    20   any
          20    23    20   any
}

javap並沒有將字節碼反編譯成成java文件,而是生成一種另一種能看的懂得字節碼。可以看出被synchronized修飾的代碼包含 monitorenter 和 monitorexit。synchronized 底層依賴着兩個指令來實現同步, 這里看起來比較晦澀難懂。

CFR

官網上下載jar,執行如下命令:

java -jar cfr-0.151.jar SynchronizedTest.class

得到反編譯java文件:

public class SynchronizedTest {
    private int count = 0;

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public void addOne() {
        Class<SynchronizedTest> clazz = SynchronizedTest.class;
        synchronized (SynchronizedTest.class) {
            ++this.count;
            // ** MonitorExit[var1_1] (shouldn't be in output)
            return;
        }
    }
}

CFR還帶有一些參數:

參數 注釋
--decodeenumswitch (boolean) 去除switch對枚舉支持的語法糖
--decodelambdas (boolean) 去除lambda表達式的語法糖
--decodestringswitch (boolean) 去除switch string支持的語法糖

其余參數可使用如下命令查看:

 java -jar cfr-0.151.jar --help 

idea

使用idea生成class文件,用idea打開class文件即可。idea是絕大多數Java程序員使用的編輯器,使用idea打開文件比較方便、快捷。

參考

Java代碼的編譯與反編譯那些事兒
javap的使用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM