拿到一个陌生的 jar 包想看看里面怎么实现的,你第一个反应是什么?JD-GUI?IDEA 自带反编译?还是粘到在线工具?

这篇文章把目前主流的 4 种反编译方式做了实机对比——覆盖 Java 8 到 Java 21 的字节码、Lambda / Records / Switch Expression 等新语法、混淆处理 和 匿名内部类,告诉你什么场景用什么工具。

反编译的本质

编译是 .java → .class(字节码),反编译是 .class → .java(源码近似)。反编译出来的代码永远是近似:

  • 变量名丢失(javac -g:vars 能保留,但生产 jar 默认不带)
  • 注释完全丢失(编译时被丢弃)
  • 局部变量类型丢失(可能变成 Object)
  • 某些语法糖还原不了(如 assert、foreach 循环)

所以反编译工具拼的就是:还原度有多高、新语法支持有多快、混淆处理多强。

四种工具实机对比

工具 1:JD-GUI(桌面软件)

老牌反编译工具,打开 jar 直接能看。优点:零配置、速度快、支持导出源码包。缺点:Java 16+ 的新语法(records、sealed classes)还原度差,混淆处理弱。

适用场景:快速扫一眼 jar 结构、看简单类的方法签名。

工具 2:IDEA 自带反编译(JetBrains Decompiler)

IDEA 2017+ 内置,打开 class 文件自动触发。优点:和 IDE 无缝集成、能跳转引用、和本地源码联动。缺点:功能有限(不能一键导出整个 jar、对混淆无能为力),需要有 IDEA 环境。

适用场景:调试时想看依赖 jar 某个类的实现细节。

工具 3:CFR(开源,命令行)

目前还原度最高的开源反编译器之一,持续更新。支持 Java 8-21 的新语法、匿名类、Lambda、Records、Switch Expression。优点:还原度最高、混淆处理强、可作为库嵌入自己的工具。缺点:命令行学习成本、不如 GUI 直观。

java -jar cfr.jar MyClass.class --outputdir ./src

工具 4:在线反编译(本项目工具)

Java 在线反编译 把单个 .class 文件粘到浏览器里直接出源码,结果可复制或下载为 .java。优点:零安装、浏览器即开即用、无需 JDK 环境,底层用 CFR 引擎,还原度和命令行一致。缺点:线上版保持轻量,只支持单个 class(最大 1MB)——整包 jar 解析适合放到本地离线处理,规划在本地工具箱(DXTool 桌面版)中提供。现阶段需先用 jar xf 解压再逐个上传;混淆重的 class 还原后变量名不可读。

还原度测试

语法特性 JD-GUI(典型表现) IDEA 自带(典型表现) CFR / 在线(典型表现)
Java 8 Lambda ✅ ✅ ✅
Java 9 Module 系统 ❌ ⚠️ ✅
Java 14 Records ❌ ⚠️ ✅
Java 14 Switch Expression ❌ ⚠️ ✅
Java 17 Sealed Class ❌ ❌ ✅
匿名内部类 ✅ ✅ ✅
匿名类里的 this ❌(变量名错) ⚠️ ✅
混淆处理 ⚠️(反混淆弱) ⚠️ ✅(容错强,变量名仍需 mapping 还原)
局部变量名保留 ❌ ❌ ❌(需要 -g:vars 编译)

表中为各工具在常见版本上的典型表现(❌ 表示不支持或还原明显出错、⚠️ 表示支持但不完整),并非逐版本实测结论;换用具体版本时以实际输出为准。

选择建议

  • 快速扫一眼:IDEA 自带反编译 或 在线反编译(单 class)
  • 需要源码包:CFR 命令行 或 在线工具下载 .java 文件
  • 混淆重的 jar:CFR 对混淆字节码容错较好,但变量名仍是 a/b/c,需配合 ProGuard/R8 的 mapping 文件人工对照
  • 跨语言字节码(Kotlin / Scala):CFR 支持基础还原,需要对应语言的反编译插件

反编译出来的代码能直接用吗?

不能,原因:

  1. 变量名丢失(反编译成 a、b、c 或 var)
  2. 注释全丢
  3. 某些局部变量类型丢失变成 Object
  4. Kotlin 的 data class、suspend fun 等特性还原后不是 Kotlin 代码

能参考,用于看实现逻辑、找依赖、排查版本差异。不能直接拿去当源码提交。

相关工具

  • Java 在线反编译:CFR 引擎,支持 Java 8-21,匿名类/Lambda/Records/Switch Expression 还原
  • Java 转 TypeScript:反编译出的 Java 类一键转 TypeScript interface,用于前后端接口定义对齐