bigywater.tech
常见报错 · 47

Java UnsupportedClassVersionError: class file version 65.0:JDK 17/21/27 九种组合,-source/-target 不检查 API 到运行时才 NoSuchMethodError,jar 里混版本用到才报

“has been compiled by a more recent version of the Java Runtime” 在升级 JDK、换 CI 镜像、引入新依赖后经常出现。这篇用本机三个 JDK 把组合跑全:报错里的数字对应哪个 Java、--release 和 -source/-target 差在哪、为什么有时到用到某个类才报,以及怎么确认手里的 class 和 JDK 到底是什么版本。

65 → 61
用 JDK 21 编译、JDK 17 运行:class file version 65.0 大于本 JDK 认得的 61.0
NoSuchMethodError
-source 17 -target 17 编译用了 JDK 21 才有的 List.reversed(),到 JDK 17 上才出错;--release 17 则编译期就拒绝
JDK 17
这个实验环境里直接敲 java 实际用到的版本,Homebrew 装的 21、27 要用完整路径

9 种组合

实测 · 本机执行输出
  用 JDK 17 编译(默认):Main.class 的 major version = 61
      在 JDK 17 上运行 -> 成功:Hello from Java 17,运行在 Eclipse Adoptium
      在 JDK 21 上运行 -> 成功:Hello from Java 21,运行在 Homebrew
      在 JDK 27 上运行 -> 成功:Hello from Java 27,运行在 Homebrew
  用 JDK 21 编译(默认):Main.class 的 major version = 65
      在 JDK 17 上运行 -> 失败(退出码 1),class file version 65.0,本 JDK 只认到 61.0
      在 JDK 21 上运行 -> 成功:Hello from Java 21,运行在 Homebrew
      在 JDK 27 上运行 -> 成功:Hello from Java 27,运行在 Homebrew
  用 JDK 27 编译(默认):Main.class 的 major version = 71
      在 JDK 17 上运行 -> 失败(退出码 1),class file version 71.0,本 JDK 只认到 61.0
      在 JDK 21 上运行 -> 失败(退出码 1),class file version 71.0,本 JDK 只认到 65.0
      在 JDK 27 上运行 -> 成功:Hello from Java 27,运行在 Homebrew
  JDK 27 编译、JDK 17 运行的完整报错:
      Error: LinkageError occurred while loading main class Main
      	java.lang.UnsupportedClassVersionError: Main has been compiled by a more recent version of the Java Runtime (class file version 71.0), this version of the Java Runtime only recognizes class file versions up to 61.0

运行 JDK 不能比编译 JDK 低(没设 --release 时)。

怎么读数字

实测 · 本机执行输出
  JDK 21 加 --release 8:major version = 52
  JDK 21 加 --release 11:major version = 55
  JDK 21 加 --release 17:major version = 61
  JDK 21 加 --release 21:major version = 65
  JDK 27 加 --release 17:major version = 61(JDK 27 的 javac 仍能 --release 17)
  这个 class 在 JDK 17 上运行:退出码 0,输出 Hello from Java 17,运行在 Eclipse Adoptium
  --release 与 -source/-target 的差别:-source 17 -target 17 只管语法和 class 版本,不检查你调用的 API 是否存在于 17
  JDK 21 用 -source 17 -target 17 编译用到 List.reversed()(21 才有的 API):编译成功
      在 JDK 17 上运行(退出码 1):
          Exception in thread "main" java.lang.NoSuchMethodError: 'java.util.List java.util.List.reversed()'
          	at Main.main(Main.java:2)
  同样的代码改用 --release 17:编译失败
      Main.java:2: error: cannot find symbol
      public class Main { public static void main(String[] a) { System.out.println(java.util.List.of(1, 2, 3).reversed()); } }
                                                                                                             ^

用 major version 对照,用 --release 做向下兼容,而不是 -source/-target。

延迟报错

实测 · 本机执行输出
  Main.class major = 61;Helper.class major = 65
  JDK 17,不触碰 Helper(退出码 0,用时 0.03 s):
      main 开始
      main 结束
  JDK 17,用到 Helper(退出码 1,用时 0.03 s):
      main 开始
      Exception in thread "main" java.lang.UnsupportedClassVersionError: Helper has been compiled by a more recent version of the Java Runtime (class file version 65.0), this version of the Java Runtime only recognizes class file versions up to 61.0
      	at java.base/java.lang.ClassLoader.defineClass1(Native Method)
      	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1017)
      	at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
      …(共 12 行)

版本过高的类到加载时才报,冷门分支可能上线后才爆。

确认版本

实测 · 本机执行输出
  javap -v Helper:minor version: 0 |   major version: 65
  用 file 命令看:<tmp>/mix/Helper.class: compiled Java class data, version 65.0
  jar 里 Main.class:major version = 61
  jar 里 Helper.class:major version = 65
  macOS 上 /usr/bin/java 指向哪个 JDK:openjdk version "17.0.20.1" 2026-08-18;JAVA_HOME=(未设置)
  /usr/libexec/java_home 默认选的:/Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home
  终端 PATH 里排第一的 java:/usr/bin/java

javap -v、file、逐个读 jar;并检查 java -version 与 JAVA_HOME。

分步演示

class 版本
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64;报错文本都是真实复现时原样捕获的(命令行工具统一用 LC_ALL=C 取英文原文,路径换成 );所有服务都是本机上自己起的、只监听 127.0.0.1,不访问外网;计时用 time.perf_counter,数字每次运行会有小幅抖动。本篇用 Temurin 17.0.20.1、Homebrew openjdk@21 21.0.13、Homebrew openjdk 27;每个程序是 javac 编译后 java 直接运行的小 Main.java;major version 都是从各 JDK 实际编出的 class 文件第 7、8 字节读出来的
    • 没有验证:Maven、Gradle 里 maven.compiler.release / sourceCompatibility 的具体配置(只验证了 javac 的 --release);Spring Boot 之类框架对最低 JDK 的要求;IDE 里 Project SDK 与运行配置错位的情形;jlink / jpackage 自带运行时的情形;Linux 上多个 JDK 用 update-alternatives 切换;预览特性(--enable-preview)产生的 minor version 65535
    京ICP备2026067502号-1京公网安备11010502063487号