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及更早版本的source
和target
如我们的示例所示,为了在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开始,使用source
或target
为1.5或更早版本已弃用,而在JDK 9中,对source
或target
为1.5或更早版本的支持已被完全移除。
6. Java 9及更高版本的source
和target
尽管在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
选项。