javac默认编译流程共七个关键阶段:Parse(词法语法分析生成AST)、Enter(构建符号表)、Process(注解处理)、Attribution(类型与语义检查)、Flow(控制流分析)、Desugar(语法糖降级)、Generate(字节码生成)。

Java 源代码编译不是简单地把 .java 文件“翻译”成 .class 文件,而是一套分阶段、带语义检查的流程;直接用 javac 命令看似一步完成,背后实际包含词法分析、语法解析、符号表构建、注解处理、字节码生成等多个逻辑阶段。
javac 的默认编译流程分哪几个关键阶段
从 javac 启动到输出 .class,核心阶段包括:
-
Parse:读入源码,做词法和语法分析,生成抽象语法树(AST),此时只检查基础语法(如括号是否匹配、if后是否跟括号) -
Enter:将类、方法、字段等符号填入符号表,建立作用域关系;此阶段失败会报cannot find symbol -
Process:运行注解处理器(如 Lombok、MapStruct 的@Data或@Mapper),可能生成新源文件或修改 AST -
Attribution:类型检查与语义分析,确认变量类型、方法重载、泛型擦除后是否合法;incompatible types、bad operand types都在此阶段抛出 -
Flow:控制流分析,检查变量是否初始化、是否可达、是否有 unreachable code -
Desugar:将高阶语法糖(如 lambda、try-with-resources、switch 表达式)降级为 JVM 支持的字节码结构 -
Generate:遍历 AST,生成符合 JVM 规范的.class字节码(含常量池、字段/方法表、Code 属性等)
为什么加了 -Xlint 能发现更多问题
-Xlint 不是开启新阶段,而是让 Attribution 和 Flow 阶段启用更严格的检查规则。默认情况下,很多潜在问题(如未使用的变量、过时 API 调用、序列化 UID 缺失)被静默忽略。
-
javac -Xlint:all会报告所有可检测的警告,比如serial(缺少serialVersionUID)、fallthrough(switch 中漏写break) -
-Xlint:-unchecked可关闭某类警告,但要注意:关闭unchecked不会跳过泛型类型擦除检查,只是不提示“未经检查的转换”这类信息 - 部分
-Xlint提示(如dep-ann)依赖源码中是否存在@Deprecated注解,不是仅靠字节码推断
编译时报错 “class file for XXX not found” 是哪个阶段的问题
这是 Enter 阶段失败的典型表现——符号表构建时找不到依赖类的定义。它和运行时的 NoClassDefFoundError 容易混淆,但发生时机完全不同。
rebuild是一款高度可配置化的企业管理系统!可免费商用!低代码/零代码快速搭建企业中台、OA办公自动化、CRM客户关系管理、WMS库存管理、TMS运输管理、SCM供应链管理,甚至是 ERP 企业资源计划!REBUILD 侧重于业务需求实现,而非基础技术框架或项目启动模板,通过 REBUILD 可以真正实现零代码快速搭建,无需编程、无需编译代码,甚至无需了解技术。 使用开始使用 REBUIL
立即学习“Java免费学习笔记(深入)”;
- 常见原因:类路径(
-cp或-classpath)没包含该类所在的 JAR 或目录;或模块路径(--module-path)未正确配置模块依赖 - 注意:即使该类在运行时可通过 classloader 加载,编译期也必须显式可见;
javac不会去扫描整个lib/目录猜依赖 - 若用 Maven,确保
compilescope 的依赖已正确声明;IDE 中有时缓存了旧 classpath,需刷新项目(如 IntelliJ 的Reload project)
真正影响编译结果的,不是你写了什么语法,而是符号表怎么建、类型怎么推、注解怎么展开;很多“明明能跑通却编译不过”的问题,根源都在 Enter 或 Attribution 阶段的隐式约束上。









