javac
javac 是 JDK 内置的 Java 源码编译器,将 .java 文件编译为 JVM 可执行的 .class 字节码。
基本用法
javac [选项] <源文件># 编译单个文件
javac Hello.java
# 编译多个文件
javac Foo.java Bar.java
# 编译整个目录下所有 Java 文件(借助 shell 展开)
javac src/**/*.java
# 使用 @argfile 传入文件列表(避免命令行过长)
javac @sources.txt常用选项
| 选项 | 说明 |
|---|---|
-d <dir> | 指定 .class 输出目录 |
-cp / -classpath <path> | 指定编译时类路径 |
-sourcepath <path> | 指定源码搜索路径 |
-encoding <charset> | 源文件字符编码(常用 UTF-8) |
-source <version> | 源码兼容版本(如 17) |
-target <version> | 生成字节码的目标版本 |
--release <version> | 同时设置 source/target 并锁定 API(推荐) |
-g | 生成完整调试信息(行号、变量名、源文件) |
-g:none | 不生成任何调试信息 |
-verbose | 打印每个编译的类 |
-Xlint | 开启所有推荐警告 |
-Xlint:<key> | 开启指定警告(如 -Xlint:unchecked) |
-proc:none | 禁用注解处理器 |
-processor <class> | 指定注解处理器 |
-parameters | 在字节码中保留方法参数名 |
编译阶段(内部流程)
源码字符流
│
▼ 词法分析(Scanner)
Token 流
│
▼ 语法分析(Parser)
抽象语法树(AST)
│
▼ 注解处理(Annotation Processing)
可能产生新源文件,重新编译
│
▼ 语义分析
├─ 符号表填充
├─ 类型检查 / 推导
├─ 常量折叠
└─ 去糖(Desugar):lambda、switch 表达式、record 等
│
▼ 字节码生成(Gen)
.class 文件
去糖(Desugar):javac 会在生成字节码前将高级语法(增强 for、try-with-resources、lambda 等)转换为等价的低级结构,JVM 无需感知这些语法糖。
版本兼容
# 推荐做法:--release 同时约束源码语法、目标字节码、可用 API
javac --release 17 Hello.java
# 老做法:仅约束字节码版本,但不限制 API 使用
javac -source 17 -target 17 Hello.java注解处理器(APT)
javac 内置注解处理(APT)支持,在编译阶段执行代码生成(如 Lombok、MapStruct):
# 显式指定处理器及生成源码的输出目录
javac -processor com.example.MyProcessor -s generated-src Hello.java
# 禁用所有处理器(加快编译)
javac -proc:none Hello.java查看字节码
编译后可用 javap 反汇编查看指令:
# 查看方法字节码
javap -c Hello.class
# 显示完整信息(常量池、签名等)
javap -verbose Hello.class如需还原为 Java 源码,参见 fernflower。