Menu

如何运行 Java:用 javac 编译,用 java 运行

每个 Java 程序背后都是先编译、再运行的两步流程:用 javac 把 .java 源代码变成字节码,再用 java 运行 .class 文件。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

先编译,再运行

装好 JDK 之后,运行 Java 就是一个两步的流程。脚本语言只要把解释器指向一个文件就能运行,Java 则不同:它先把人类可读的源代码编译成字节码,然后由单独的一步在 JVM 上运行这些字节码。

这两步对应着 JDK 自带的两个命令行工具:

  • javac:编译器。它读取 Main.java,写出 Main.class(字节码)。
  • java:启动器。它启动 JVM 并执行 Main.class 中的字节码。

任何独立的示例都可以直接在本页运行,下面的编辑器会替你完成这两步。不过,弄清楚在你自己的电脑上发生了什么还是很有价值的,因为真正的项目都在那里。

在你电脑上的两条命令

假设你把这段代码保存为 Main.java:

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello from the terminal");
    }
}

在存放该文件的文件夹中打开终端,运行编译器:

javac Main.java

如果代码编译顺利,javac 什么都不会打印,而是在源文件旁边生成一个新文件 Main.class。这个 .class 文件就是字节码:它不是可读的文本,也不依赖于你的操作系统。

现在用 java 命令启动它:

java Main
Hello from the terminal

初学者最常犯的错误就在这里:启动程序用的是 java,而不是 javac,并且要传入不带扩展名的类名。写 java Main,永远不要写 java Main.class,也不要写 java Main.java。

文件名必须与公共类同名

Java 有一条让新手意外的规则:public 类必须放在名字完全相同、再加上 .java 的文件里。public class Main 必须在 Main.java 中。大小写写错了,javac 就会拒绝编译。

// This is in a file called Greeting.java
public class Greeting {   // ERROR: class Greeting should be in Greeting.java... wait, it is
    public static void main(String[] args) {
        System.out.println("Hi");
    }
}

真正让人栽跟头的不匹配要隐蔽得多:类名是 Greeting,文件却命名为 greeting.java(小写);或者保存为 Main.java,里面却写的是 public class Hello。编译器会报出类似这样的错误:

Main.java:1: error: class Hello is public, should be declared in a file named Hello.java

解决方法永远一样:让文件名和公共类名一模一样,一个字符都不差。

捷径:直接运行单个文件

从 JDK 11 开始,单个源文件可以跳过显式的编译步骤。java 命令会在内存中编译它并一次性运行,不会往磁盘写入 .class 文件:

java Main.java

这非常适合快速试验和小脚本。注意传入内容的区别:

  • java Main:运行一个已经编译好的 Main.class。
  • java Main.java:一步完成源文件的编译和运行。

单文件模式只在整个程序都放在一个文件里时才有效。一旦你把代码拆分到多个文件中的多个类里,就要回到先用 javac 编译的方式。学习基础知识时,单文件模式能让“修改、运行”的循环更短。

给程序传递参数

还记得 main 里的 String[] args 吗?那就是命令行参数。在 java 命令中类名之后输入的任何内容,都会进入这个数组:

在你自己的电脑上,可以这样给它传入参数:

java Main hello world
First argument: hello
Total arguments: 2

上面的编辑器无法接收终端参数,所以它运行的是“没有参数”的分支,但同一段代码能处理两种情况。这就是 Java 程序读取启动时传入的输入的方式,远在你接触文件或用户输入之前。

读懂编译器的错误信息

当 javac 拒绝你的代码时,它会告诉你文件、行号以及出了什么问题。学会读这些信息,就解决了一半的卡壳问题。下面是一个经典例子,漏了分号:

public class Main {
    public static void main(String[] args) {
        System.out.println("Oops")   // no semicolon
    }
}
Main.java:3: error: ';' expected
        System.out.println("Oops")
                                  ^
1 error

插入符号(^)指向编译器期望出现某样东西的位置。Main.java:3 是文件名和行号。不要急着瞎猜:读一读那一行,修复它指出的那一个问题,然后重新编译。编译错误意味着还什么都没运行;运行时错误(看起来不一样)则意味着程序已经启动,然后失败了。

一个自检程序

在编辑器里运行它,或者把它保存为 Main.java,在你自己的电脑上先执行 javac Main.java 再执行 java Main。如果三行都打印出来了,说明你的工具链从头到尾都能正常工作:

这里出现了三样你很快就会正式学到的东西:一个 int 变量、用 + 拼接字符串,以及一个数组和它的 .length。现在只要程序能编译并打印出来就够了。

下一页:Java 语法

你已经运行了几个程序,但我们一直没细说那些符号:花括号、分号、public static void main,以及为什么每一行都长成这样。下一页会逐一拆解 Java 的语法,让这些结构不再像是照抄的模板,而是真正说得通。

常见问题

如何运行 Java 程序?

把代码保存在以公共类命名的文件中(例如 Main.java),在该文件夹中打开终端,然后运行两条命令:javac Main.java 把它编译成字节码,再用 java Main 运行它。使用 JDK 11 或更新版本时,单个文件可以跳过第一步,直接运行 java Main.java。

javac 和 java 有什么区别?

javac 是编译器:它读取你的 .java 源代码,生成一个装满字节码的 .class 文件。java 是启动器:它启动 JVM 并运行 .class 文件中的字节码。用 javac 编译一次,之后用 java 想运行多少次都可以。

为什么会出现“找不到或无法加载主类”(could not find or load main class)?

几乎都是因为你传给 java 的名字不对。要用类名,而不是文件名:写 java Main,而不是 java Main.class 或 java Main.java。还要确认你所在的文件夹里有 Main.class,并且类名与文件名完全一致,包括大小写。

Coddy 编程语言插图

和 Coddy 一起学编程

开始