编译不同版本的 Java

Java 编程语言(及其运行时)自其首次公开发布以来发布以来经历了许多变化。这些变化包括:

  • Java 编程语言语法和语义的变化
  • Java 标准类库提供的 API 的更改。
  • Java(字节码)指令集和类文件格式的更改。

除了极少数例外(例如 enum 关键字,对某些内部类的更改等),这些更改是向后兼容的。

  • 使用较旧版本的 Java 工具链编译的 Java 程序将在较新版本的 Java 平台上运行,无需重新编译。
  • 使用旧版 Java 编写的 Java 程序将使用新的 Java 编译器成功编译。

使用较新的编译器编译旧 Java

如果你需要(重新)在较新的 Java 平台上编译较旧的 Java 代码以在较新的平台上运行,则通常不需要提供任何特殊的编译标志。在少数情况下(例如,如果你使用 enum 作为标识符),你可以使用 -source 选项来禁用新语法。例如,给定以下类:

public class OldSyntax {
    private static int enum;  // invalid in Java 5 or later
}

使用 Java 5 编译器(或更高版本)编译类需要以下内容:

$ javac -source 1.4 OldSyntax.java

编译旧的执行平台

如果需要编译 Java 以在较旧的 Java 平台上运行,最简单的方法是为需要支持的最旧版本安装 JDK,并在构建中使用该 JDK 的编译器。

你也可以使用较新的 Java 编译器进行编译,但这很复杂。首先,必须满足一些重要的先决条件:

  • 你编译的代码不得使用你所定位的 Java 版本中不可用的 Java 语言结构。
  • 代码不能依赖于旧平台中不可用的标准 Java 类,字段,方法等。
  • 代码所依赖的第三方库也必须为较旧的平台构建,并在编译时和运行时可用。

在满足前提条件的情况下,你可以使用 -target 选项重新编译旧平台的代码。例如,

$ javac -target 1.4 SomeClass.java

将编译上面的类以生成与 Java 1.4 或更高版本 JVM 兼容的字节码。 (实际上,-source 选项意味着兼容的 -target,因此 javac -source 1.4 ... 会产生相同的效果。在 Oracle 文档中描述了 -source-target 之间的关系。)

话虽如此,如果你只是使用 -target-source,你仍然会编译编译器的 JDK 提供的标准类库。如果你不小心,最终可能会得到具有正确字节码版本的类,但依赖于不可用的 API。解决方案是使用 -bootclasspath 选项。例如:

$ javac -target 1.4 --bootclasspath path/to/java1.4/rt.jar SomeClass.java

将针对另一组运行时库进行编译。如果正在编译的类具有(意外)依赖于较新的库,则会给出编译错误。