1. 概述

在这个教程中,我们将探讨Java编译器提供的-source-target选项,并了解它们在Java 8及以后版本中的工作原理,以及它们如何演变。

2. 向后兼容旧版Java

由于Java频繁发布和更新,应用程序可能无法每次都迁移到最新版本。有时,应用程序需要确保其代码能够与较旧的Java版本兼容。javac-source-target选项使得实现这一点变得简单。

首先,我们创建一个示例类,并使用Java 9引入但Java 8不支持的List.of()方法:

public class TestForSourceAndTarget {
    public static void main(String[] args) {
        System.out.println(List.of("Hello", "Baeldung"));
    }
}

假设我们使用Java 9进行编译,但希望与Java 8兼容。我们可以使用-source-target来实现:

/jdk9path/bin/javac TestForSourceAndTarget.java -source 8 -target 8

现在,我们在编译时会收到警告,但编译成功:

warning: [options] bootstrap class path not set in conjunction with -source 8
1 warning

在Java 8中运行代码,我们会看到错误:

$ /jdk8path/bin/java TestForSourceAndTarget
Exception in thread "main" java.lang.NoSuchMethodError: ↩
  java.util.List.of(Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/List;
  at com.baeldung.TestForSourceAndTarget.main(TestForSourceAndTarget.java:7)

理想情况下,Java应在编译时抛出此错误。然而,在编译时,我们仅收到了警告。

让我们看看编译时收到的警告。javac告知我们bootstrap类与-source 8不兼容。事实证明,我们必须提供bootstrap类文件路径,以便javac可以在跨编译时找到正确的文件。在我们的例子中,我们想要兼容Java 8,但默认选择了Java 9的bootstrap类。

为了使这个工作,我们需要使用-Xbootclasspath指向所需跨编译的Java版本的路径

/jdk9path/bin/javac TestForSourceAndTarget.java -source 8 -target 8 -Xbootclasspath ${jdk8path}/jre/lib/rt.jar

现在,让我们编译它,我们会在编译时看到错误:

TestForSourceAndTarget.java:7: error: cannot find symbol
        System.out.println(List.of("Hello", "Baeldung"));
                               ^
  symbol:   method of(String, 
String)
  location: interface List
1 error

3. 源选项

-source选项指定了编译器接受的Java源代码版本:

/jdk9path/bin/javac TestForSourceAndTarget.java -source 8 -target 8

如果没有-source选项,编译器将根据所使用的Java版本编译源代码。

-source值为8意味着我们不能使用任何特定于Java 9的API,如List.of()。要使用Java 9引入的任何API,如List.of(),我们必须将-source值设置为9。

4. 目标选项

-target选项指定了生成的类文件所需的Java版本。目标发布必须等于或高于-source选项:

/jdk9path/bin/javac TestForSourceAndTarget.java -source 8 -target 8

这里,-target 8意味着这将生成一个需要Java 8或更高版本才能运行的类文件。如果在Java 7中运行上述类文件,我们会遇到错误。

5. Java 8及更早版本的sourcetarget

如我们的示例所示,为了在Java 8中正确地进行跨编译,我们需要提供三个选项:-source-target-Xbootclasspath例如,如果我们需要使用Java 9构建代码,但需要兼容Java 8:

/jdk9path/bin/javac TestForSourceAndTarget.java -source 8 -target 8 -Xbootclasspath ${jdk8path}/jre/lib/rt.jar

从JDK 8开始,使用sourcetarget为1.5或更早版本已弃用,而在JDK 9中,对sourcetarget为1.5或更早版本的支持已被完全移除。

6. Java 9及更高版本的sourcetarget

尽管在Java 8中跨编译可以正常工作,但需要三个命令行选项。当有三个选项时,可能会难以保持它们的更新。

作为Java 9的一部分,引入了-release选项来简化跨编译流程。使用-release选项,我们可以完成与以前选项相同的跨编译。

让我们使用-release选项来编译我们之前的示例类:

/jdk9path/bin/javac TestForSourceAndTarget.java —release 8
TestForSourceAndTarget.java:7: error: cannot find symbol
        System.out.println(List.of("Hello", "Baeldung"));
                               ^
  symbol:   method of(String,String)
  location: interface List
1 error

明显地,编译时只需要一个选项-release,错误表明javac已经内部为-source-target-Xbootclasspath分配了正确的值。

7. 总结

在这篇文章中,我们学习了javac-source-target选项及其与跨编译的关系。我们还了解了这些选项在Java 8及以后版本中的使用方式,以及Java 9中引入的-release选项。