Java编译核心是将.java转为.class字节码,可用javac、IDE或Maven/Gradle;需注意-source/-target匹配、类路径、包结构、构建工具配置及注解处理器集成。

Java 程序编译的核心就是把 .java 源文件转换成 JVM 能执行的 .class 字节码,这件事不一定要用 javac 命令手动敲——但绝大多数情况下,你得先搞清楚它默认怎么工作,否则其他方式容易出错。
javac 命令行编译:最基础也最容易翻车
这是 JDK 自带的标准编译器,路径在 $JAVA_HOME/bin/javac。它看似简单,但几个参数稍不注意就导致类找不到或版本不兼容:
-
-source和-target必须匹配——比如用 JDK 17 编译却加了-source 8 -target 8,生成的字节码能跑,但若用了var或switch表达式就会报错 - 类路径(
-cp或-classpath)只影响编译期查依赖,不影响运行;漏掉第三方.jar会导致cannot find symbol - 包结构必须和目录结构严格一致:声明
package com.example;就得放在com/example/MyClass.java路径下,否则javac报class is public and must be declared in a file named - 多个源文件一起编译时,不用显式列全,用
javac com/example/*.java更稳,避免遗漏内部类生成的$文件
IDE 内置编译器(IntelliJ / Eclipse):自动但不透明
它们默认不调用系统 javac,而是用自己的增量编译引擎(如 IntelliJ 的 javac fork 或 Eclipse JDT Compiler),好处是快、支持实时错误提示,坏处是行为可能和命令行不一致:
- IntelliJ 默认启用
Build project automatically,但不会重新编译被删掉的.class文件,残留旧字节码可能引发NoClassDefFoundError - Eclipse 的编译器对泛型擦除更宽松,某些在
javac下报错的代码(如模糊的类型推断)可能通过,上线后运行时报ClassCastException - 务必检查 IDE 的
Project SDK和Language level是否与pom.xml或build.gradle里声明的一致,否则编译通过、打包失败
Maven / Gradle 编译:工程化场景的实际标准
真正项目里几乎没人手敲 javac,而是靠构建工具统一管理源码位置、依赖和 Java 版本:
立即学习“Java免费学习笔记(深入)”;
- Maven 默认从
src/main/java编译,用maven-compiler-plugin控制 JDK 版本:和17 必须同时设,只设一个可能被忽略17 - Gradle 中
java { sourceCompatibility = JavaVersion.VERSION_17 }只控制语法检查,真正字节码版本由compileJava.options.release = 17决定(推荐用release而非target,它会禁用跨版本 API) - 多模块项目中,子模块编译依赖父模块的
target/classes,不是 jar 包——所以mvn compile不会触发 install,本地修改父模块后要先mvn compile再编译子模块,否则报symbol not found
注解处理器(APT)和编译期代码生成:编译不只是翻译
像 Lombok、MapStruct、Dagger 这类工具,是在 javac 编译过程中插入处理器,动态生成代码。这阶段出问题往往没有明确错误提示,只有运行时报空指针或类不存在:
- Lombok 需要在 IDE 插件 + 编译插件(如
lombok-maven-plugin)两端都启用,缺一不可;Gradle 中还要加annotationProcessor 'org.projectlombok:lombok' - 自定义注解处理器必须在
META-INF/services/javax.annotation.processing.Processor里声明全限定名,否则javac -processor找不到它 - 处理器生成的源码默认放在
target/generated-sources/annotations,Maven 要用build-helper-maven-plugin把该路径加入编译源目录,否则编译失败
编译不是黑盒流水线,尤其当涉及 APT、多模块或 IDE 与构建工具混用时,javac 的输出路径、类路径、目标版本这三个变量一旦错位,错误现象就可能分散在编辑器报红、编译成功但运行失败、CI 构建通过但本地失败等不同环节——盯住 javac -verbose 或 Maven 的 -X 日志,比猜更快。










