1.4 常见编译与运行错误
前置知识:Java 基本语法规则
预计时间:20 分钟
完成标志:能区分 shell、编译器和 Java 启动器报告的问题
“别急着复制整段报错去搜索。先问:这句话是谁说的?”
先分清三个阶段
| 阶段 | 示例命令 | 常见报告者 | 说明 |
|---|---|---|---|
| 查找并启动工具 | javac ... | shell | 命令不存在、工具无法执行 |
| 编译源码 | javac -d out HelloWorld.java | javac | 语法、类型、公开类文件名等问题 |
| 加载并执行类 | java -cp out HelloWorld | Java 启动器或程序 | 类路径、入口方法、运行时异常 |
诊断措辞会随 JDK、操作系统和语言环境变化。下面只保留定位问题所需的关键片段,不要求逐字背诵。
1. 找不到 javac
javac: command not found这不是 Java 源码错误。shell 在 PATH 中没找到编译器。
command -v javac
javac --version若第一条没有输出,确认安装的是 JDK,并按发行版说明配置 PATH。不要通过反复修改 Hello World 来解决环境问题。
2. 找不到源文件
error: file not found: HelloWorld.java检查当前目录和真实文件名:
pwd
ls -la常见原因包括大小写不同、隐藏的 .txt 后缀,或者终端尚未进入保存文件的目录。
3. 公开类与文件名不一致
代表性诊断:
class HelloWorld is public, should be declared in a file named HelloWorld.java若源文件实际叫 hello.java,修复文件名:
mv hello.java HelloWorld.java
javac -d out HelloWorld.javaLinux 文件系统通常区分大小写;Windows 默认行为常不同。Java 名称本身仍区分大小写。
4. 漏分号或括号
error: ';' expected先看指示位置,再向前检查完整语句。解析器只能在“无法继续理解”时报告问题,所以根因可能在箭头前面。
漏掉右花括号时常见:
error: reached end of file while parsing从最内层开始核对 ()、[]、{} 和引号是否闭合。不要为了让错误消失就在文件末尾盲目堆 }。
5. 名称拼错:cannot find symbol 等诊断
system.out.println("Hello");system 与标准库类 System 不是同一个名字。这里 javac 通常报告 package system does not exist;把 println 拼错则常见 cannot find symbol。看完整诊断,确认出问题的是限定名、方法还是变量。
类似问题:
| 写错 | 正确 | 类型 |
|---|---|---|
system | System | 类名大小写 |
string | String | 类名大小写 |
System.Out | System.out | 字段名大小写 |
printl | println | 方法拼写 |
6. 找不到主类
Could not find or load main class HelloWorld按顺序检查:
find out -type f -name 'HelloWorld.class' -print
java -cp out HelloWorld- 第一条没有结果:编译是否成功,
-d out是否写对; - 文件存在:运行时类路径是否仍指向
out; - 类在包中:启动时必须使用完整限定名,本章暂不使用包;
- 不要把
.class后缀传给java。
ClassNotFoundException 也可能由程序运行时加载其他类失败引发,不能把所有同类文字都归因于“忘了编译”。
7. 找不到入口方法
传统 Java 17 示例需要:
public static void main(String[] args)拼成 Main、mian,漏掉 static,改成非 void 返回类型,都会使启动器无法把它当作传统入口。
但这两种写法本身有效:
public static void main(String words[]) { }
public static void main(String... words) { }所以排错时要检查类型与修饰符,不要把参数变量名或方括号位置误判为唯一合法形式。
8. 旧字节码掩盖新错误
javac 失败不会自动删除上一次成功生成的 .class。如果随后直接运行,旧程序仍可能启动,让人误以为新源码生效了。
test ! -e out || rm -r -- out
mkdir out
javac -d out HelloWorld.java && java -cp out HelloWorld&& 让运行命令只在编译成功后执行。这里只删除当前练习目录中的 out。先用 pwd 确认位置,不要把递归删除命令改成更宽泛的路径。
通用排查循环
重现一次
↓
记录完整命令、当前目录、第一条错误
↓
判断是 shell、编译还是运行阶段
↓
只改一个明确原因
↓
从编译开始重新验证离开这一页前
拿到一条报错,先说出它来自 shell、javac 还是 Java 启动器,再用 pwd、ls 和产物目录核对。记住两个容易误判的边界:错误箭头不保证落在最初根因上,编译失败也不会替你删除旧 .class。
下一页把这些错误安全地制造一次,再亲手修掉。