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(为了方便后续的学习,我们还会讲如何切换回低版本),参考教程可以参考我写的另一篇博客:Java 多版本配置 (opens new window)
# 用 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)
- 01
- 中国网络防火长城简史 转载10-12
- 03
- 公告:博客近期 RSS 相关问题10-02