Appearance
Class Version
In Java development, many children are often confused by various versions of JDK. In this section, we will explain in detail the class file version issue after the Java program is compiled.
What we usually call Java 8, Java 11, and Java 17 refer to the JDK version, which is the JVM version. To be more precise, it is the version of the java.exe
program:
sh
$ java -version
java version "17" 2021-09-14 LTS
Each version of the JVM has different versions of class files that it can execute. For example, the class file version corresponding to Java 11 is 55, and the class file version corresponding to Java 17 is 61.
If you compile a Java program with Java 11, the output class file version defaults to 55. This class can run on either Java 11 or Java 17, because the class file version supported by Java 17 is 61, which means "at most Supported up to version 61".
If you compile a Java program with Java 17, the output class file version will be 61 by default. It can run on Java 17 and Java 18, but it is impossible to run on Java 11 because Java 11 supports class versions up to 55. If you run it with a JVM lower than Java 17, you will get an UnsupportedClassVersionError
with a similar error message:
sh
java.lang.UnsupportedClassVersionError: Xxx has been compiled by a more recent version of the Java Runtime...
As long as you see UnsupportedClassVersionError
, it means that the version of the class file currently being loaded exceeds the capabilities of the JVM, and a higher version of the JVM must be used to run it.
For example, if you save a Word file in Word 2013, this file can also be opened in Word 2016. But conversely, if you save a Word file with Word 2016, you cannot open it with Word 2013.
However, wait a minute, you can also save a file in the format of Word 2013 using Word 2016, so that the saved Word file can be opened with an earlier version of Word 2013, but the premise is that the file format must be clearly specified when saving to be compatible with Word 2013.
Similarly, corresponding to the JVM class file, we can also use Java 17 to compile a Java program and specify that the output class version must be compatible with Java 11 (i.e. class version 55), so that the compiled class file can be used in Java >= 11 environment.
There are two ways to specify compilation output. One is to use the parameter --release
setting in the javac
command line:
sh
$ javac --release 11 Main.java
The parameter --release
11 indicates that the source code is compatible with Java 11, and the compiled class output version is compatible with Java 11, that is, class version 55.
The second way is to use the parameter --source
to specify the source code version and the parameter --target
to specify the output class version:
sh
$ javac --source 9 --target 11 Main.java
If the above command is compiled using the Java 17 JDK, it will treat the source code as a Java 9 compatible version and output the class as a Java 11 compatible version. Note that the --release
parameter and --source --target
parameter can only be selected from the two and cannot be set at the same time.
However, there are some potential problems if the specified version is lower than the current JDK version. For example, we compile Hello.java
with Java 17 and set the parameters --source 9
and --target 11
:
sh
public class Hello {
public static void hello(String name) {
System.out.println("hello".indent(4));
}
}
Running Hello
with a JVM lower than Java 11 will get a LinkageError
because the Hello.class
file cannot be loaded, while running Hello
with Java 11 will get a NoSuchMethodError
because String.indent()
method was only added from Java 12, Java The String
version of 11 has no indent()
method at all.
Notice
If --release 11
is used, it will be checked at compile time whether the method exists in Java 11.
Therefore, if the JVM version at runtime is Java 11, it is best to use Java 11 when compiling instead of using a higher version of JDK to compile and output a lower version of the class.
If you do not specify any version parameters when compiling with javac
, it is equivalent to using --release [current version]
, that is, both the source code version and the output version are the current version.
During the development phase, multiple versions of JDK can be installed at the same time, and the currently used JDK version can be switched by the JAVA_HOME
environment variable.
Source code version
When writing source code, we usually preset a version of the source code. When compiling, if you specify the source code version with --source
or --release
, the specified source code version is used to check the syntax.
For example, the source code version using lambda expressions must be at least 8 to compile, the source code version using the var
keyword must be at least 10 to compile, the source code version using switch
expressions must be at least 12 to compile, and 12 and 13 The version requires the --enable-preview
parameter to be enabled.
Summary
A higher version of the JDK can compile and output class files that are compatible with a lower version. However, it should be noted that the lower version of the JDK may not have the classes and methods added by the higher version of the JDK, resulting in an error when running.
Which JDK version is used at runtime? Try to use the same version of JDK to compile the source code when compiling.