class版本
# class版本
不同JDK版本生成的class文件版本也不同。
# 前言
Java有很多个版本,我们通常说的Java 8,Java 11,Java 17,是指JDK的版本,也就是JVM的版本,更确切地说,就是java.exe
这个程序的版本:
> java -version
java version "1.8.0_351"
2
class文件也有对应版本。例如,Java8对应的class文件版本是52, Java 11是55,而Java 17是61。
目前用的最广泛的是Java8,这就涉及到一些版本的问题:
- 那如果后续升级了JDK版本,还能运行之前用低版本的Java编译后的class文件吗?可以的;
- 如果后续降级了JDK版本,还能运行高版本的Java编译后的class文件吗?不可以,需要重新编译。
这里引用廖雪峰老师的比喻:
打个比方,用Word 2013保存一个Word文件,这个文件也可以在Word 2016上打开。但反过来,用Word 2016保存一个Word文件,就无法使用Word 2013打开。
但是,且慢,用Word 2016也可以保存一个格式为Word 2013的文件,这样保存的Word文件就可以用低版本的Word 2013打开,但前提是保存时必须明确指定文件格式兼容Word 2013。
接下来我们可以实践一下,同时一个高版本的Java(为了方便后续的学习,我们还会讲如何切换回低版本),更多参考https://www.peterjxl.com/Java/Java-install-multi-version
# 用Java11编写和运行代码
我们先切换到Java11,新建和运行Java代码:
新建一个Hello11.java文件,代码如下
public class Hello11{
public static void main(String[] args){
System.out.println("Hello Java11 !");
}
}
2
3
4
5
> javac Hello11.java
> java Hello11
Hello Java11 !
2
3
切换到Java8之前,我们先查看class版本:
D:\DownLoad>javap -v Hello11.class
Classfile /D:/DownLoad/Hello11.class
Last modified 2022年11月27日; size 422 bytes
MD5 checksum d35ca922fd955c1886c8c143c0a2ccea
Compiled from "Hello11.java"
public class Hello11
minor version: 0
major version: 55
2
3
4
5
6
7
8
第8行就是class文件的版本:55. 后面还有更多关于该class文件的信息,这里不表。
# 用Java8运行Java11的代码
接下来,我们切换回Java8,然后尝试运行:
D:\DownLoad>java Hello11
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.UnsupportedClassVersionError: Hello11 has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
2
3
可以看到有报错UnsupportedClassVersionError,这个就是因为class版本不兼容的问题。
# 查看Java8的class文件版本
我们尝试用Java8重新编译,然后查看class文件版本
D:\DownLoad>javap -v Hello11.class
Classfile /D:/DownLoad/Hello11.class
Last modified 2022-11-27; size 422 bytes
MD5 checksum 08ed42a4993c6150bd3bcf66dd0873b3
Compiled from "Hello11.java"
public class Hello11
minor version: 0
major version: 52
2
3
4
5
6
7
8
可以看到class文件的版本为52
# 尝试用Java11运行Java8的class
Java版本大部分情况下都是向后兼容的,也就是高版本的Java能运行低版本的class文件。
我们试着运行,没有问题,Java代码能正常执行:
D:\DownLoad>javap -v Hello11.class
Classfile /D:/DownLoad/Hello11.class
Last modified 2022年11月27日; size 422 bytes
MD5 checksum 08ed42a4993c6150bd3bcf66dd0873b3
Compiled from "Hello11.java"
public class Hello11
minor version: 0
major version: 52
D:\DownLoad>java Hello11
Hello Java11 !
2
3
4
5
6
7
8
9
10
11
12
# 指定编译出来的class文件版本
我们可以让Java11编译出来的class文件兼容Java8,只需在命令行里指定版本即可。
第一种方式:使用--release选项
javac --release 8 Hello11.class
参数--release 8
表示源码兼容Java8
第二种方式:使用--source 和 --target选项
javac --source 9 --target 11 Main.java
参数--source
指定源码版本,参数--target
指定输出class版本。
注意:
- 两种方式不能混用,例如又用--source,又用--release。
- 有些Java11的新特性(例如String类的新方法indent),只能在Java11运行。即使指定了兼容Java8,在Java8也运行不了。但如果使用--release 11则会在编译时检查该方法是否在Java 11中存在。
- 如果使用
javac
编译时不指定任何版本参数,那么相当于使用--release 当前版本
编译,即源码版本和输出版本均为当前版本。
# 小结
高版本的JDK可编译输出低版本兼容的class文件,但需注意,低版本的JDK可能不存在高版本JDK添加的类和方法,导致运行时报错。
运行时使用哪个JDK版本,编译时就尽量使用同一版本编译源码。
# 参考
本文主要参考了廖雪峰老师的博客:class版本 - 廖雪峰的官方网站 (opens new window)