1. Overview
1.概述
In this tutorial, we’ll learn about Java 9’s new command-line option –release. The Java compiler running with the –release N option automatically generates class files compatible with Java version N. We’ll discuss how this option relates to the existing compiler command-line options -source and -target.
在本教程中,我们将了解Java 9的新命令行选项-release。使用-release N选项运行的Java编译器会自动生成与Java版本N兼容的类文件。我们将讨论这个选项与现有的编译器命令行选项-source和-target的关系。
2. Need for —release Option
2.需要-释放选项
To understand the need for a —release option, let us consider a scenario where we need to compile our code with Java 8 and want the compiled classes to be compatible with Java 7.
为了理解对-release选项的需求,让我们考虑这样一种情况:我们需要用Java 8编译我们的代码,并希望编译后的类能与Java 7兼容。
It was possible to achieve this before Java 9 by using the —source and —target options, where
在Java 9之前,可以通过使用-source和-target选项来实现,其中
- -source: specifies the Java version accepted by the compiler
- -target: specifies the Java version of the class files to produce
Suppose the compiled program uses APIs exclusively available in the current version of the platform, in our case, Java 8. In that case, the compiled program cannot run on earlier versions like Java 7, regardless of the values passed to the –source and –target options.
假设编译后的程序只使用平台当前版本的API,在我们的例子中是Java 8。在这种情况下,无论传递给-source和-target选项的值如何,编译后的程序都不能在早期版本(如Java 7)上运行。
Furthermore, we would need to add the –bootclasspath option along with –source and –target to work in Java versions 8 and below.
此外,我们需要将-bootclasspath选项与-source和-target一起加入,以便在Java 8及以下版本中工作。
To streamline this cross-compilation problem, Java 9 introduced the new option —release to simplify the process.
为了简化这一交叉编译问题,Java 9引入了新的选项–release来简化这一过程。
3. Relationship With -source and -target Options
3.与-source和-target选项的关系
According to the JDK definition, –release N can be expand as:
根据JDK定义,-release N可以扩展为。
- for N < 9, -source N -target N -bootclasspath <documented-APIs-from-N>
- for N >= 9, -source N -target N –system <documented-APIs-from-N>
- -bootclasspath: a semicolon-separated list of directories, JAR archives, and ZIP archives for searching boot class files
- —system: overrides the location of system modules for Java 9 and later versions
For Java version N< 9, these APIs include the bootstrap classes retrieved from jars located in jre/lib/rt.jar and other related jars.
对于Java版本N<9,这些API包括从位于jre/lib/rt.jar和其他相关jar中检索的引导类。
For Java version N >= 9, these APIs include the bootstrap classes retrieved from the Java modules located in the jdkpath/jmods/ directory.
对于Java版本N>=9,这些API包括从位于jdkpath/jmods/目录的Java模块中检索的引导类。
4. Usage with the Command Line
4.使用命令行的方法
First, let’s create a sample class and use the overridden flip method of ByteBuffer, which was added in Java 9:
首先,让我们创建一个示例类,并使用ByteBuffer的重载flip方法,这是在Java 9中添加的。
import java.nio.ByteBuffer;
public class TestForRelease {
public static void main(String[] args) {
ByteBuffer bb = ByteBuffer.allocate(16);
bb.flip();
System.out.println("Baeldung: --release option test is successful");
}
}
4.1. With Existing -source and -target Option
4.1.使用现有的-source和-target选项
Let’s compile the code in Java 9 using the -source and -target options value as 8:
让我们使用-source和-target选项值为8,在Java 9中编译代码。
/jdk9path/bin/javac TestForRelease.java -source 8 -target 8
The result of this is successful, but with a warning:
这样做的结果是成功的,但有一个警告。
warning: [options] bootstrap class path not set in conjunction with -source 8
1 warning
Now, let’s run our code on Java 8:
现在,让我们在Java 8上运行我们的代码。
/jdk8path/bin/java TestForRelease
We see that this fails:
我们看到,这是不可能的。
Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer;
at com.corejava.TestForRelease.main(TestForRelease.java:9)
As we can see, this is not what we expected to see with the given value of 8 in our -release and -target option. So although the compiler should consider it, that’s not the case.
我们可以看到,这不是我们在-release和-target选项中给出的8的值所期望看到的。所以尽管编译器应该考虑到这一点,但情况并非如此。
Let’s understand this in more detail.
让我们更详细地了解这一点。
In releases before Java 9, the Buffer class contained the flip method:
在Java 9之前的版本中,Buffer类包含flip方法。
public Buffer flip() {
...
}
In Java 9, ByteBuffer, which extends Buffer, overrides the flip method:
在Java 9中,ByteBuffer,扩展了Buffer,覆盖了翻转方法。
@Override
public ByteBuffer flip() {
...
}
When this new method is compiled on Java 9 and run on Java 8, we get the error as both methods have different return types and method lookup using the descriptor fails at runtime:
当这个新方法在Java 9上编译并在Java 8上运行时,我们得到了错误,因为这两个方法的返回类型不同,在运行时使用描述符的方法查找失败。
Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer;
at com.corejava.TestForRelease.main(TestForRelease.java:9)
During compilation, we got the warning which we ignored earlier. This is because the Java compiler, by default, compiles with the latest APIs. In other words, the compiler used Java 9 classes even though we specified –source and –target to be 8, so our program failed to run on Java 8.
在编译过程中,我们得到了之前忽略的警告。这是因为Java编译器,默认情况下,使用最新的API进行编译。换句话说,尽管我们指定-source和-target为8,但编译器还是使用了Java 9类,所以我们的程序未能在Java 8上运行。
Therefore, we must pass another command-line option called –bootclasspath to the Java compiler to choose the correct versions.
因此,我们必须将另一个名为-bootclasspath的命令行选项传递给Java编译器以选择正确的版本。
Now, let’s recompile the same code with –bootclasspath option:
现在,让我们用-bootclasspath选项:重新编译相同的代码。
/jdk9path/bin/javac TestForRelease.java -source 8 -target 8 -Xbootclasspath ${jdk8path}/jre/lib/rt.jar
Again, the result of this is successful, and this time we don’t have any warning.
同样,这样做的结果是成功的,而这次我们没有任何警告。
Now, let’s run our code on Java 8, and we see that this is successful:
现在,让我们在Java 8上运行我们的代码,我们看到这很成功。
/jdk8path/bin/java TestForRelease
Baeldung: --release option test is successful
Although cross-compilation works now, we had to provide three command-line options.
尽管交叉编译现在可以工作,但我们不得不提供三个命令行选项。
4.2. With –release Option
4.2.带有-release选项
Now, let’s compile the same code with the –release option:
现在,让我们用-release选项编译同样的代码。
/jdk9path/bin/javac TestForRelease.java —-release 8
Again, the compilation is successful this time, with no warnings.
同样,这次编译成功了,没有任何警告。
Finally, when we run the code on Java 8, we see that it is successful:
最后,当我们在Java 8上运行该代码时,我们看到它是成功的。
/jdk8path/bin/java TestForRelease
Baeldung: --release option test is successful
We see that it’s straightforward with the —release option as javac internally sets the correct values for -source, -target, and –bootclasspath.
我们看到,使用-release选项很直接,因为javac在内部为-source,-target,和-bootclasspath设置了正确的值。
5. Usage with the Maven Compiler Plugin
5.使用Maven编译器插件的方法
Usually, we use build tools like Maven or Gradle and not the command-line javac tool. So in this section, we will see how we can apply the –release option in the maven compiler plugin.
通常,我们使用Maven或Gradle等构建工具,而不是使用命令行javac工具。所以在本节中,我们将看到如何在maven编译器插件中应用-release选项。
Let’s first see how we use the existing -source and -target options:
让我们首先看看我们如何使用现有的-source和-target选项。
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
Here’s how we can use the –release option :
下面是我们如何使用-release选项。
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>1.8</release>
</configuration>
</plugin>
</plugins>
Although the behavior is the same as we described earlier, the way we are passing these values to the Java compiler is different.
尽管行为与我们前面描述的相同,但我们将这些值传递给Java编译器的方式是不同的。
6. Conclusion
6.结语
In this article, we learned about the –release option and its relationship with the existing -source and -target options. Then, we saw how to use the option on the command line and with the Maven compiler plugin.
在本文中,我们了解了-release选项及其与现有-source和-target选项的关系。然后,我们看到了如何在命令行和Maven编译器插件中使用该选项。
Finally, we saw that the new —release option requires fewer input options for cross-compilation. For this reason, it is recommended to use it whenever possible instead of the -target, -source, and -bootclasspath options.
最后,我们看到新的 –release 选项在交叉编译中需要更少的输入选项。出于这个原因,我们建议尽可能使用它来代替-target, -source,和-bootclasspath选项。