Java 零基础教程

Java 编译与运行

编译和运行 Java 代码是 Java 开发过程中最基础也是最核心的步骤。理解这些步骤对于执行你的程序并查看代码运行结果至关重要。本章将手把手带你了解如何将 Java 源代码编译成字节码,以及随后如何使用 Java 虚拟机 (JVM) 运行这些字节码。

1. 编译过程 (The Compilation Process)

编译是将人类可读的源代码(在我们的例子中是 Java 代码)翻译成机器可执行代码的过程。然而,Java 并不是直接编译成针对你当前操作系统的底层机器码。相反,它会编译成一种中间表示形式,称为字节码 (bytecode)。这种字节码与平台无关,这意味着它可以在任何安装了 Java 虚拟机 (JVM) 的系统上运行。

1.1 从源代码到字节码

Java 编译器 javac 负责完成这项翻译工作。以下是编译期间发生的具体步骤:

  • 语法和语义分析: 编译器首先检查你的代码是否存在语法错误(例如,缺少分号、关键字拼写错误)和语义错误(例如,类型不匹配、使用了未声明的变量)。如果发现任何错误,编译过程就会停止,你需要先修复它们才能继续。
  • 代码生成: 如果代码完全没有错误,编译器就会生成字节码。字节码由 JVM 能够理解和执行的一系列指令组成。
  • 创建 Class 文件: 生成的字节码会被保存在一个 .class 文件中。这个 .class 文件的名称与你 Java 源代码文件中定义的类名完全一致(例如,HelloWorld.java 编译后会生成 HelloWorld.class)。

代码示例:

假设你有一个名为 HelloWorld.java 的简单 Java 程序:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

要编译这段代码,你需要在终端或命令提示符中输入以下命令:

javac HelloWorld.java

如果编译成功,你的 HelloWorld.java 文件所在的同一目录下将会生成一个 HelloWorld.class 文件。

1.2 处理编译错误

编译错误是日常开发中非常常见的一部分。Java 编译器会提供极其详细的错误提示信息,帮助你快速定位并修复代码中的问题。

示例:

假设你在 HelloWorld.java 程序中不小心把 System.out.println 拼写成了 System.out.prntln

public class HelloWorld {
    public static void main(String[] args) {
        System.out.prntln("Hello, World!"); // 故意的拼写错误
    }
}

当你尝试编译这段代码时,你会得到类似下面的错误提示:

HelloWorld.java:3: error: cannot find symbol
        System.out.prntln("Hello, World!");
                  ^
  symbol:   method prntln(String)
  location: variable out of class System
1 error

这段报错信息清楚地告诉了你以下关键线索:

  • 发生错误的文件名 (HelloWorld.java)
  • 发生错误的具体行号 (3)
  • 错误的描述说明 (cannot find symbol,即找不到符号)
  • 无法找到的具体符号 (method prntln(String),即找不到 prntln 这个方法)
  • 编译器寻找该符号的位置 (variable out of class System)

只要仔细阅读报错信息,你就能迅速发现并纠正拼写错误。

2. 执行过程 (The Execution Process)

一旦你成功将 Java 代码编译成了字节码,下一步就是执行它。这时候,就轮到 Java 虚拟机 (JVM) 登场了。

2.1 JVM 的核心作用

JVM 是一个专门用于执行 Java 字节码的软件环境。它充当了你编译后的代码与底层操作系统之间的“中间人”。正是这个机制赋予了 Java 跨平台的能力——同一份字节码,可以在任何配备了兼容 JVM 的系统上运行。

执行期间会经历以下步骤:

  • 加载 (Loading): JVM 将 .class 文件加载到系统内存中。
  • 字节码校验 (Bytecode Verification): JVM 严格检查字节码,确保它是合法的且没有违反任何系统安全限制。
  • 解释执行 / 即时编译 (JIT Compilation): JVM 可以直接逐条解释执行字节码,或者使用 JIT (Just-In-Time) 编译器将字节码实时翻译成底层操作系统的原生机器码,以极大地提升执行速度。现代 JVM 主要依赖 JIT 编译技术。
  • 执行 (Execution): JVM 执行字节码(或经过 JIT 编译的原生代码),精准完成你程序中指定的所有操作。

2.2 运行你的 Java 程序

要运行编译好的 Java 程序,你需要使用 java 命令,后面跟上包含 main 方法的类名(千万不要加 .class 扩展名)。

示例:

要运行我们之前创建的 HelloWorld.class 文件,请使用以下命令:

java HelloWorld

这将执行 HelloWorld 类中的 main 方法,你应该能在控制台上看到成功打印出的 "Hello, World!"。

2.3 深入理解 main 方法

main 方法是你的 Java 程序的入口点。当你运行程序时,JVM 会主动去寻找具有这种特定签名的 main 方法:

public static void main(String[] args) {
    // 你的代码写在这里
}
  • public: main 方法必须声明为 public(公开的),这样 JVM 才有权限从外部访问并启动它。
  • static: 必须声明为 static(静态的),这样 JVM 就可以在不创建该类实例(对象)的情况下直接调用它。
  • void: 表示 main 方法执行完毕后不返回任何结果值。
  • String[] args: main 方法接收一个字符串数组作为参数。这些参数是你运行程序时,可以通过命令行传递给程序的外部指令。我们将在后续模块中专门讲解命令行参数。

3. 处理运行时错误 (Runtime Errors)

运行时错误,通常被称为异常 (Exceptions),是在程序正在执行的过程中发生的错误。导致这类错误的原因有很多,比如输入了无效数据、尝试除以零,或者访问了不存在的数组元素。我们将在后续专门的模块中深入探讨异常处理机制。

示例代码:

public class Division {
    public static void main(String[] args) {
        int numerator = 10;
        int denominator = 0;
        int result = numerator / denominator; // 潜在的除以零错误
        System.out.println("结果: " + result);
    }
}

如果你运行这段代码,程序会立刻抛出一个 ArithmeticException(算术异常),因为在数学法则中你不能除以零。此时,程序会异常终止,并在控制台上打印出错误堆栈信息。

4. 使用集成开发环境 (IDE)

虽然你可以纯靠命令行来编译和运行 Java 代码,但集成开发环境 (IDE) 能为你提供更便捷、功能更丰富的开发体验。像 IntelliJ IDEA、Eclipse 和 NetBeans 这样的 IDE 能够全自动处理编译和执行过程,并提供代码自动补全、强大的调试工具等实用功能。

4.1 在 IDE 中编译和运行

在 IDE 中操作的具体步骤因软件而异,但基本流程大同小异:

  • 创建项目: 在 IDE 中新建一个 Java 项目。
  • 编写代码: 在 IDE 的智能编辑器中敲入你的 Java 代码。
  • 编译: 大多数 IDE 会在你输入代码或保存文件时进行自动编译。你也可以通过菜单或快捷键手动触发编译。
  • 运行: 要运行程序,通常只需点击一个绿色的“运行 (Run)”按钮,或者按下一个快捷键。IDE 会在后台替你完成编译(如果需要的话),然后立刻执行它。
  • 查看输出: 程序的运行结果会直接显示在 IDE 底部的控制台 (Console) 窗口中。