javac将.java源文件编译为jvm可执行的.class字节码,经历词法分析、语法检查、语义验证等步骤;它独立于ide和jre,依赖jdk配置,需严格匹配包路径、正确使用-cp/--module-path、-d指定输出目录,且不校验运行时依赖完整性。

javac 命令到底在做什么
它不是“把 Java 变成机器码”,而是把 .java 源文件翻译成 JVM 能读的 .class 字节码文件。这个过程包括词法分析、语法检查、语义验证(比如类型匹配、方法是否存在)、常量池填充,最后生成符合 JVM 规范的二进制结构。
关键点在于:javac 不依赖 IDE,也不需要运行环境(JRE),只要 JDK 安装正确、JAVA_HOME 和 PATH 配对,终端就能调用它——它本身就是一个独立的 Java 程序(javac 是 com.sun.tools.javac.Main 的封装启动器)。
编译单个文件时路径和包声明必须对齐
如果你的源码里写了 package com.example;,那这个 .java 文件就不能随便放在桌面或 src/ 根目录下编译,否则会报 error: class XXX is public, should be declared in a file named XXX.java 或更隐蔽的 error: cannot find symbol。
- 文件必须放在对应包路径下:比如
com/example/Main.java - 编译时要从**包根目录**执行:
javac com/example/Main.java(不是javac Main.java) - 如果当前在
com/example/目录下,直接javac Main.java会失败——javac 会按包名反推路径,找不到com/example/Main.java - 想绕过路径限制?加
-sourcepath或用-d指定输出目录,但包结构仍得存在
类路径(-cp)和模块路径(--module-path)容易混用
javac 默认只认当前目录和 rt.jar(基础类库),你引用了第三方 JAR 或自己写的其他类,不显式指定就必然报 cannot find symbol。
立即学习“Java免费学习笔记(深入)”;
- 用
-cp(或-classpath)告诉 javac 去哪找.class或.jar:javac -cp "lib/gson.jar:." com/example/Main.java - JDK 9+ 引入模块系统后,如果依赖的是模块化 JAR(含
module-info.class),要用--module-path,而不是-cp;混用会导致error: module not found -
-cp中的路径顺序有影响:前面的 JAR 里有同名类,会遮蔽后面的——这在调试冲突时很关键 - Windows 下分隔符是
;,不是:,写错就等于没加路径
编译输出目录(-d)不设的话,.class 会散落在源码目录里
默认情况下,javac 把生成的 .class 文件放在和 .java 同一目录。这对小项目无所谓,但一旦有包结构,就会污染源码树,后续运行 java 命令时容易因类路径混乱而报 NoClassDefFoundError。
- 统一输出到
out/目录:javac -d out com/example/Main.java - javac 会自动按包名创建子目录:
out/com/example/Main.class - 后续运行时,
java -cp out com.example.Main才能正确定位类 - 如果
-d指向不存在的目录,javac 不报错也不创建——它静默失败,.class还是落回源码目录
最常被忽略的是:javac 编译本身不校验运行时依赖是否完整,它只保证当前编译单元语法和引用可见。哪怕你漏掉一个 -cp 里的 JAR,只要没用到那个 JAR 里的类,它照样编译成功——直到运行时报错才暴露问题。











