🔍第44篇:jd-gui反编译class文件,解决中文乱码问题
📌 系列导航:《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第43篇:Java字节码,javap命令,解读字节码清单
➡️ 下一篇:基础篇终极总结:44篇通关!一张图+三张表,把全部知识点装进脑子
一、核心知识点
jd-gui工具的作用:图形化反编译.class文件为 Java 源代码- 中文乱码原因:jd-gui 默认系统编码(如 Windows GBK)与 class 文件中的 UTF-8 字符串不匹配
- 乱码解决方案:修改配置文件、命令行指定编码、使用替代工具
- 反编译的局限性:丢失泛型、局部变量名、注释;混淆代码难以反编译
- 其他反编译工具对比:CFR、Procyon、Luyten、Bytecode Viewer、IDEA 内置 FernFlower
- 防止反编译的基本手段:混淆器(ProGuard、Allatori)
- 字节码层面延伸:
-g参数与 LocalVariableTable 的关系、编译期常量优化
二、通俗讲解(1分钟开心学)
1. jd-gui 是什么?
jd-gui 是一个开源的 Java 反编译工具,可以将 .class 文件(字节码)还原成近似原始的 .java 代码。当你没有源码(比如第三方库)又想看实现逻辑时,可以用它。
生活类比:
反编译就像根据乐谱(字节码)还原出作曲家原始手稿(源码),但手稿上的一些铅笔标记(变量名、注释)已经模糊不清了。

2. 为什么有中文乱码?
jd-gui 早期版本默认使用系统编码(如 Windows 的 GBK),而 class 文件中的字符串是 UTF-8 编码。中文就会显示成乱码。最新版本(如 1.6.6 以上)已部分修复,但仍可能因环境不同而出现问题。
3. 乱码解决方案
- 下载最新版 jd-gui(1.6.6+),可能已修复。
- 修改
jd-gui.cfg配置文件,添加jdk.lang.encoding=UTF-8。 - 命令行启动时指定编码(见下方多系统适配):
java -Dfile.encoding=UTF-8 -jar jd-gui-1.6.6.jar - 使用替代工具:IDEA 内置 FernFlower(日常开发首选)、Luyten(基于 Procyon)、Bytecode Viewer、CFR(命令行优先推荐)。
4. 反编译的局限性
- 泛型信息擦除,反编译后可能变成
Object。 - 局部变量名被替换为
var1、var2等。 - 注释完全丢失。
- 经过混淆(如 ProGuard)的代码几乎不可读。
三、jd-gui 操作全流程与替代工具对比
3.1 基本操作
- 下载 jd-gui(官网
java-decompiler.github.io) - 双击运行,将
.class文件或.jar包拖入窗口 - 左侧树形结构浏览类,右侧显示反编译源码
- 菜单
File → Save All Sources可保存所有源码
3.2 乱码解决实战
Windows 系统:
创建 start-jdgui.bat:
@echo off
javaw -Dfile.encoding=UTF-8 -jar jd-gui-1.6.6.jar
Mac / Linux 系统:
终端启动命令:
java -Dfile.encoding=UTF-8 -jar jd-gui-1.6.6.jar
或创建 start-jdgui.sh:
#!/bin/bash
java -Dfile.encoding=UTF-8 -jar jd-gui-1.6.6.jar
3.3 IDEA 内置 FernFlower(日常开发首选)
IntelliJ IDEA 自带 FernFlower 反编译引擎,无需安装任何插件,无中文乱码问题。
使用方式:
- 在 IDEA 中打开项目依赖的 jar 包,点击任意
.class文件 - IDEA 会自动反编译并显示源码(若未关联源码包)
- 可通过
File → Settings → Build, Execution, Deployment → Compiler → Java Decompiler调整反编译设置
优势:无缝集成、无乱码、支持 Java 8+ 语法(lambda、switch 表达式等),适合日常开发查看第三方库源码。
3.4 替代工具对比
| 工具 | 特点 | 适用场景 |
|---|---|---|
| jd-gui | 图形化,简单易用 | 快速查看单个 class |
| IDEA FernFlower | 内置集成,无乱码 | 日常开发首选 |
| CFR | 命令行,支持 Java 8+ 语法(lambda、switch 表达式) | 批量反编译、高版本 Java |
| Procyon | 对泛型、枚举处理较好 | 对泛型反编译质量要求高 |
| Luyten | 基于 Procyon 的图形化版本 | 图形化 + 高质量反编译 |
| Bytecode Viewer | 集成多种反编译引擎,可切换 | 需要对比不同引擎结果 |
CFR 常用命令:
# 基础反编译
java -jar cfr.jar ChineseDemo.class
# 指定输出目录(批量反编译 jar)
java -jar cfr.jar myapp.jar --outputdir ./src
# 保留变量名(反编译时保留原始变量名)
java -jar cfr.jar ChineseDemo.class --renamedupmembers false
# 指定编码(避免乱码)
java -Dfile.encoding=UTF-8 -jar cfr.jar ChineseDemo.class
四、实操代码案例 + 场景说明
1. 准备一个带中文的类:
// ChineseDemo.java
public class ChineseDemo {
public static void main(String[] args) {
System.out.println("你好,世界!");
String 姓名 = "张三";
System.out.println(姓名);
}
}
2. 编译并测试乱码:
javac -encoding UTF-8 ChineseDemo.java
用 jd-gui 打开 ChineseDemo.class,早期版本可能显示乱码。使用上面提供的启动脚本解决。
3. 使用 CFR 反编译(无乱码):
java -jar cfr.jar ChineseDemo.class
输出效果:
public class ChineseDemo {
public static void main(String[] arrstring) {
System.out.println("你好,世界!");
String string = "张三";
System.out.println(string);
}
}
(注意:局部变量名被替换为 arrstring、string)
4. 反编译 JAR 包实战:
# 解压 jar 包或直接反编译
java -jar cfr.jar my-library.jar --outputdir ./decompiled
五、避坑要点(高频踩坑汇总)
| 错误/误区 | 后果 | 正确做法 |
|---|---|---|
| 认为反编译能 100% 恢复源码 | 丢失信息,无法直接编译 | 仅供学习参考 |
| 依赖反编译进行调试 | 可能被混淆误导 | 尽量获取真实源码或使用调试符号 |
| 反编译商业软件 | 可能侵权 | 遵守软件许可,仅用于合法学习 |
| jd-gui 无法打开高版本 Java 的 class | 解析错误 | 使用支持高版本的 CFR 或 Procyon,或 IDEA FernFlower |
| 忽视乱码问题 | 中文显示为乱码,无法阅读 | 设置 -Dfile.encoding=UTF-8 或用其他工具 |
| 混淆后的代码反编译后仍不可读 | 浪费时间 | 结合字符串解密、动态调试分析 |
编译时未加 -g 参数 | 反编译后局部变量名全部变为 var1、var2 | 需要调试信息时,编译加 -g |
| 依赖 IDEA FernFlower 反编译时忽略 | 日常查看第三方库不够高效 | 学会 IDEA FernFlower 使用,作为日常开发默认方案 |
六、面试高频考点(附详细答案)
Q1:反编译的原理是什么?
解析
.class文件的字节码结构,根据 JVM 规范将指令序列还原成 Java 语法树。由于丢失了局部变量名、泛型参数、注释等信息,无法完全恢复。
Q2:有哪些常见的 Java 反编译工具?
jd-gui、IDEA FernFlower(日常首选)、Luyten(基于 Procyon)、CFR、FernFlower(IntelliJ IDEA 内置)。CFR 对 Java 8+ 语法支持较好,Procyon 对泛型处理优秀。
Q3:如何防止自己的代码被反编译?
使用混淆器(ProGuard、Allatori、Zelix KlassMaster)增加阅读难度;将核心逻辑放在服务端;使用 native 方法(JNI)加密关键部分。
Q4:为什么反编译后的代码变量名变成 var1、var2?
编译时如果没有加上
-g参数(生成调试信息),局部变量名不会被保留在 class 文件中。反编译工具只能使用临时名称。即使加了-g,仍可通过混淆工具去掉变量名。
Q5:jd-gui 中文乱码的根本原因和解决方法?
根本原因是 jd-gui 默认使用系统编码(如 GBK),而 class 文件中字符串是 UTF-8。解决方法:① 下载最新版;② 启动脚本添加
-Dfile.encoding=UTF-8;③ 修改配置文件;④ 换用 CFR 等命令行工具或 IDEA FernFlower。
Q6:如何反编译一个完整的 JAR 包并保存为 Java 源文件?
使用 CFR:
java -jar cfr.jar app.jar --outputdir ./src。jd-gui 也可通过File → Save All Sources保存。
Q7:反编译工具与 javap 命令的区别?(专栏联动)
javap输出的是字节码指令(如aload_0、invokevirtual),用于分析 JVM 执行细节;反编译工具输出的是近似 Java 源码,用于理解业务逻辑。两者配合使用:想看底层执行流程用javap -c,想快速看懂第三方库逻辑用反编译工具。
七、练习题(附参考答案)
-
动手:下载 jd-gui 或 CFR,反编译一个简单的 HelloWorld.class,对比源码差异。
💡 提示:编译时不加
-g参数,反编译后观察变量名变化。 -
排查:如果你的 jd-gui 显示中文乱码,尝试至少两种方法解决并记录。
💡 方案一:启动时加
-Dfile.encoding=UTF-8;方案二:换用 IDEA FernFlower。 -
分析:为什么混淆后的代码反编译后仍然难以阅读?结合 ProGuard 原理说明。
💡 思路:ProGuard 会重命名类名/方法名/变量名为短名称(如 a、b、c),移除调试信息,内联短方法,使得反编译结果完全不可读。
-
实战:找一个开源 JAR 包(如 Guava),用 CFR 反编译并查看源码结构。
💡 命令示例:
java -jar cfr.jar guava-xxx.jar --outputdir ./guava-src -
思考:反编译工具是否能够完全恢复 Lambda 表达式?为什么?
💡 思路:不能完全恢复。Lambda 表达式编译后会被转换为
invokedynamic指令,生成匿名内部类或方法句柄,反编译工具只能还原为近似代码,无法恢复原始的 Lambda 语法糖写法。
📊 你的学习进度
- 当前:第44篇 / 共44篇 · 第六阶段:NIO、泛型、JVM内幕、字节码(第36~44篇)
- ✅ 已完成:第1~43篇
- 📖 正在学:第44篇(基础篇技术文章最后一篇)
- ⏳ 下一步:阅读基础篇终极总结,巩固全部知识点
👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇
💡 本专栏每篇都包含:避坑表 + 面试高频考点 + 练习题。每天30分钟,100天拿offer!
🎯 基础篇技术内容已完结,但学习还在继续
恭喜你完成了基础篇全部44篇技术文章的学习!从Java跨平台原理到字节码反编译,你已经打下了扎实的Java功底。
接下来强烈建议你阅读:
👉 《44篇通关!Java基础篇终极总结:一张图+三张表,把全部知识点装进脑子》
—— 这是一份浓缩版的复习资料,包含完整学习路线图、知识点速查表、高频面试题汇总、避坑清单,以及进阶篇预告和PDF福利。
读完总结,你将把44篇零散的知识点串联成体系,面试复习效率提升3倍。
再下一步: 进阶篇(64篇)即将开启,涵盖集合源码、并发编程、JavaWeb、Spring核心、SpringBoot、MyBatis、Redis、MySQL、消息队列、分布式架构、微服务、JVM、设计模式、海量数据、手写代码、面试压轴难题全栈技术考点。
👉 订阅专栏,第一时间收到更新!
种一棵树最好的时间是10年前,其次是现在。
👉 点击关注我(第一时间收到进阶篇更新)
📌 除了《Java 100 天进阶之路 | 从入门到上岗就业》系列文章,我也在深挖智能物流实战(出版社WMS、托盘调度、机器学习落地)。如果你对技术在不同领域的实战感兴趣,欢迎点击我的头像,看看专栏《出版社物流WMS智能调度实战》。技术相通,思路可鉴。
&spm=1001.2101.3001.5002&articleId=161293537&d=1&t=3&u=a4a5d32c12fe467290a11cd2a7c137af)

被折叠的 条评论
为什么被折叠?



