
java 编译器(javac)在编译主类时会自动编译缺失的依赖类,但不会检测已存在 class 文件是否过期;因此修改源码后若不重新编译,可能导致运行时行为异常。
java 编译器(javac)在编译主类时会自动编译缺失的依赖类,但不会检测已存在 class 文件是否过期;因此修改源码后若不重新编译,可能导致运行时行为异常。
在 Java 项目中,类之间往往存在强依赖关系——如 GameLauncher 依赖 GuessGame,而 GuessGame 又依赖 Player。当你执行 javac GameLauncher.java 时,编译器确实具备按需自动编译缺失依赖的能力:它会扫描源码中引用的类(如 GuessGame),若发现当前目录下仅有 GuessGame.java 而无对应的 GuessGame.class,便会自动编译该文件;同理递归处理 Player.java。
然而,这一机制存在关键限制:javac 不做增量判断。例如,若你已编译过 GuessGame.java 并生成了 GuessGame.class,之后又修改了 Player.guess() 的实现逻辑,但未手动重新编译 Player.java,那么 javac GameLauncher.java 将直接复用旧的 Player.class,导致运行时仍返回默认值(如 0),而非你新写的逻辑结果。
这正是你观察到“仅编译主类时猜测值始终为 0,全部重编后恢复正常”的根本原因——旧 Player.class 中 guess() 方法体为空或仅含 return 0;,而更新后的源码未生效。
✅ 正确做法示例:
立即学习“Java免费学习笔记(深入)”;
# 方式1:显式编译全部源文件(适合小型项目) javac GameLauncher.java GuessGame.java Player.java # 方式2:使用通配符(确保当前目录含所有 .java) javac *.java # 方式3:删除所有 class 文件后重新编译(最稳妥的“强制刷新”) rm *.class javac GameLauncher.java
⚠️ 注意事项:
-
javac的自动编译仅限同一目录下的.java文件;若依赖类位于其他包或路径,必须通过-cp或-sourcepath显式指定; - 不要依赖“自动编译”来管理大型项目——它无法识别跨模块依赖、注解处理器或资源变更;
- 生产环境中应使用构建工具(如 Maven、Gradle),它们内置依赖图分析与增量编译能力,可精准定位并编译被修改类及其下游消费者。
总结:Java 编译器的设计目标是“最小可行编译”,而非“智能构建”。理解其“有源则编,有类则用,不查时效”的行为逻辑,是避免诡异运行时 Bug 的第一步;而迈向可靠协作开发,则必须交由专业的构建系统接管编译生命周期。


















