javac默认按系统编码读取源文件,Windows常用GBK、Linux/macOS常用UTF-8;解决中文乱码须显式指定-encoding UTF-8(或对应真实编码),且该参数必须紧邻文件名前,如javac -encoding UTF-8 HelloWorld.java。

javac 默认使用操作系统的默认字符编码读取 .java 源文件,Windows 上通常是 GBK,Linux/macOS 一般是 UTF-8。一旦源文件里含中文、注释或字符串用了非默认编码(比如 UTF-8 文件被 javac 当 GBK 解码),就会报 error: unmappable character 或乱码编译错误。
用 -encoding 参数显式指定源文件编码
这是最直接、最可靠的方式。必须在 javac 命令中紧挨着文件名之前写,顺序不能错:
javac -encoding UTF-8 HelloWorld.java
常见组合:
-
javac -encoding UTF-8 *.java—— 批量编译当前目录所有 UTF-8 编码的源文件 -
javac -encoding GBK LegacyCode.java—— 显式告诉javac这是个旧项目,用 GBK 解码 -
javac -encoding ISO-8859-1 HttpUtil.java—— 处理某些遗留 HTTP 协议字符串字面量
注意:-encoding 只影响源代码读取,不影响生成的 .class 字节码内容,也不影响运行时 String 的内部表示(Java 字符串始终是 UTF-16)。
立即学习“Java免费学习笔记(深入)”;
IDE 里改了编码,命令行 javac 还报错?
IDE(如 IntelliJ、Eclipse)能自动识别并转换源文件编码,但它们的设置对终端里的 javac 完全无效。你看到 IDE 不报错,不代表文件本身编码就“安全”了。真实情况可能是:
- IDE 把 UTF-8 文件悄悄转成了 GBK 再保存(但没提示),
javac恰好能读通 - IDE 用 UTF-8 打开文件,但未真正保存为 UTF-8(BOM 存在与否、换行符类型都可能干扰)
- 你用
file -i HelloWorld.java(Linux/macOS)或chcp+ 记事本另存为(Windows)确认实际编码,比依赖 IDE 更可信
javac 不指定 -encoding 时到底用什么?
它不看 LANG、LC_ALL 或 Windows 的“系统区域设置”,而是调用 JVM 启动时的 sun.jnu.encoding 和底层平台 API 推导。结果高度依赖 JDK 版本和 OS:
- JDK 17+ 在 macOS/Linux 上通常 fallback 到 UTF-8;Windows 上仍倾向 GBK(即使终端是 UTF-8)
- JDK 8 在中文 Windows 上几乎总是 GBK,哪怕你改了控制台
chcp 65001 - 没有
-encoding参数时,javac不会报“编码未指定”,而是静默用错编码,导致编译通过但运行时报String内容异常
所以,只要源文件含非 ASCII 字符(包括中文注释、日志文本、正则表达式),就该把 -encoding UTF-8 当作标配参数加进去,别赌默认值。
构建工具里怎么配?
Maven、Gradle 等默认不继承 shell 的编码设定,必须显式声明:
- Maven:在
pom.xml里加<project.build.sourceencoding>UTF-8</project.build.sourceencoding> - Gradle:在
build.gradle里写compileJava.options.encoding = "UTF-8" - Ant:
<javac encoding="UTF-8" ...></javac>
这些配置最终都会翻译成 javac -encoding UTF-8 调用。漏配的话,CI 流水线(尤其是 Linux 机器)极大概率编译失败——因为本地 Windows 开发环境和服务器默认编码不一致。
最易被忽略的一点:编码问题往往在跨团队协作或 CI 构建时才暴露,而错误信息里根本不会提“编码”二字,只显示“非法字符”或“类名不匹配”。这时候第一反应不该是删中文,而是立刻检查 javac -encoding 是否缺失。



















