"sourceCompatibility"和"targetCompatibility"之间有什么区别?

198
sourceCompatibilitytargetCompatibility之间有什么关系/区别?当它们被设置为不同的值时会发生什么?
根据Gradle文档中的工具链和兼容性部分以及Java插件,可以得到以下解释:
- sourceCompatibility是“编译Java源代码时使用的Java版本兼容性”。 - targetCompatibility是“生成类文件所用的Java版本”。
我的理解是,targetCompatibility将生成与特定版本的Java兼容的Java字节码。这是否是sourceCompatibility功能的一个子集?
6个回答

129

targetCompatibilitysourceCompatibility分别对应javac中的-target release-source release。其中source表示源代码的语言级别,而target则是生成的字节码所需的级别。

更多细节可以在Java 8, Java 11, Java 17或Java 19的Tools Reference中的Cross-Compilation Options for javac部分找到。Java 8Java 11Java 17Java 19皆可。


1
以上链接指向Java 7的文档。我想知道你是否需要类似于https://docs.oracle.com/en/java/javase/11/tools/javac.html#GUID-AEEC9F07-CB49-4E96-8BC7-BCC2C7F725C9这样的内容? - Brian Agnew

96

使用这些选项时要小心;我们曾经因为人们做出了一些假设而受到打击。

仅仅因为您使用了1.5的sourceCompatibility(或targetCompatibility),并不意味着您总是可以在JDK 1.6下编译您的代码,并期望它在JDK 1.5下工作。问题在于可用的库。

如果您的代码碰巧调用了JDK 1.6中才有的某个方法,即使使用了与目标VM相关的各种兼容性选项,它仍将编译。但是当您运行代码时,它会因为缺少该方法而失败(您将收到MethodNotFoundException或ClassNotFoundException)。

出于这个原因,我 总是 将Compatibility设置与实际正在构建的Java版本进行比较。如果它们不匹配,我就会让构建失败。


5
这是一个微妙但非常重要的观察。 - Natix
2
你如何进行比较? - secondbreakfast
14
如果(JavaVersion.current()!= JavaVersion.VERSION_1_8)则抛出GradleException(“此项目需要Java 8,但正在运行的是”+ JavaVersion.current())。 这就是我在build.gradle文件开头解决这个问题的方法。 - xeruf
3
自从Java 9以后,现在有一个新的javac选项--release,旨在解决这个问题,只允许使用指定Java版本中可用的API。了解更多请参见https://dev59.com/RVgQ5IYBdhLWcg3wORZJ#43103038。 - James Mudd
通常是这样的。当IDE有语言级别设置时,它通常指的是语言结构,例如lambda是否有效等。它不知道哪些方法添加到了哪个Java版本的标准库中。因此,它将只针对IDE使用的JVM进行编译。如果您想确保这一点,请使用您所针对的版本的JVM,并且不要依赖这些版本选项。 - James Mudd
显示剩余2条评论

48

sourceCompatibility = 指定编译.java文件所使用的Java编程语言版本。 例如 sourceCompatibility 1.6 = 指定使用Java编程语言版本1.6来编译.java文件。

默认情况下,sourceCompatibility =“当前JVM版本号”,targetCompatibility = sourceCompatibility

targetCompatibility = 此选项确保生成的类文件与由targetCompatibility指定的VM兼容。请注意,在大多数情况下,-target选项的值是-source选项的值;在这种情况下,您可以省略-target选项。

类文件将在targetCompatibility指定的目标上运行,以及更新版本,但不会在早期版本的VM上运行。


我们如何确定我们的项目正在使用哪些? - isJulian00

3
已经有很多关于sourceCompatibilitytargetCompatibility的好解释了,你可以在这里找到更多相关文章:Gradle: sourceCompatiblity vs targetCompatibility。但是,我建议使用Gradle的toolchain(请参见JVM项目的工具链),这将使releasesourceCompatibility调整变得不再必要,并保证语言特性(sourceCompatibility)、字节码(targetCompatibility)和Java-API/-Libraries(release)与Java版本匹配。(唯一的缺点是IDE支持尚未完全建立,但正在努力中)。

“工具链使releasesourceCompatibility调整过时”的参考资料:https://blog.gradle.org/java-toolchains。我花了一些时间才找到它。 - Shreck Ye

2
在我看来,“sourceCompatibility”意味着您可以在源代码中使用哪些功能。例如,如果您将sourceCompatibility设置为1.7,则即使您的jdk版本为1.8,也无法使用lambda表达式这个新功能。
至于“targetCompatibility”,它表示生成的类文件可以在哪个版本的jre上运行,如果将其设置为1.8,则可能无法在jdk 1.7上成功运行,但通常可以在更高版本的jdk上运行。

这真的详细解释了与开发有关的内容。 - Victor Choy

0

这些是javac命令的标志。

javac [options] [sourcefiles]

Options:
...
-source release - Specifies the version of source code accepted.
...
-target release - Generates class files for a specific VM version.
...

换句话说:您在版本中编写代码,并将类编译为目标VM版本。这样,您就可以在其他工作站上运行它,即使那些工作站使用较旧的Java版本。
根据:https://docs.oracle.com/en/java/javase/11/tools/javac.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接