javac

返回 JDK 工具 | → 编译与运行

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


相关链接

  • 编译与运行 — 编译到运行的完整流程
  • JVM — 字节码执行环境
  • JIT — 运行时热点编译
  • CFG — 编译器内部控制流图