JDK 是向下兼容的,这意味着:
为旧版本JDK编写的Java代码,可以在新发布的JDK上进行编译
使用旧版本JDK编译生成的class文件,可以在新发布的JRE上运行
但是如果有这样一个项目,它既可以用JDK8编译运行,也可以用JDK9编译运行,当我用Maven打包时,将Maven的运行环境设置为JDK9,将目标字节码版本设置为JDK8(从class文件的bytecode version看是52.0)。那这个包能在 JRE8 下运行吗。
答案是:不一定。
这个问题是我在研究 lwjgl/debug 项目时发现的,该项目是一个 javaagent 项目,至少需要支持JDK8,但由于诸多原因,项目本身使用JDK13来进行开发。该项目默认使用字节码级别为 JDK8 来进行编译。但最终在JDK8上运行时报出
Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.rewind()Ljava/nio/ByteBuffer; 复现该问题可以使用一个简单的demo来复现该问题,源代码很简单
import java.nio.ByteBuffer; public class Problem { public static void main(String[] args) { ByteBuffer buffer = ByteBuffer.allocateDirect(14); buffer.rewind(); } }将开发环境设置为 JDK 9
这里选择 8 和 9 都可以,不影响
字节码版本选择 1.8
确保打包环境使用JDK9
D:\Github\common-learn\package-problem>java -version openjdk version "9.0.4" OpenJDK Runtime Environment (build 9.0.4+11) OpenJDK 64-Bit Server VM (build 9.0.4+11, mixed mode)确保打包目标平台为 JDK8
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target>然后进行编译
D:\Github\common-learn\package-problem>mvn clean package [INFO] Scanning for projects... [INFO] [INFO] --------------------< org.example:package-problem >--------------------- [INFO] Building package-problem 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ package-problem --- [INFO] Deleting D:\Github\common-learn\package-problem\target [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ package-problem --- [INFO] Using \'UTF-8\' encoding to copy filtered resources. [INFO] Copying 0 resource [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ package-problem --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to D:\Github\common-learn\package-problem\target\classes [INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ package-problem --- [INFO] Using \'UTF-8\' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory D:\Github\common-learn\package-problem\src\test\resources [INFO] [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ package-problem --- [INFO] Nothing to compile - all classes are up to date ] [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ package-problem --- [INFO] No tests to run. [INFO] [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ package-problem --- [INFO] Building jar: D:\Github\common-learn\package-problem\target\package-problem-1.0-SNAPSHOT.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.161 s [INFO] Finished at: 2020-11-17T16:38:48+08:00 [INFO] ------------------------------------------------------------------------编译好的 Problem.class 文件从打好的jar包中取出来,然后在 JDK8 环境下运行:
D:\Github\common-learn\package-problem\target>java -version openjdk version "1.8.0_275" OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_275-b01) OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.275-b01, mixed mode) D:\Github\common-learn\package-problem\target>java Problem Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.rewind()Ljava/nio/ByteBuffer; at Problem.main(Problem.java:6) 原因rewind 这个方法,在 JDK8 中,只存在于 Buffer中,而在JDK9中,ByteBuffer 也 override 了这个方法。所以初次遇到这个问题,大概就会往这个方向猜,但是又会很困惑,即使JDK8里的 ByteBuffer 里没有 rewind 方法,可是它的父类里有啊,怎么可能 NoSuchMethod呢。