说明java运行时(java)和编译器(javac)来自不同jdk实例,环境已混装,可能导致unsupportedclassversionerror;必须保证主版本号一致,且javac决定可用语法、java决定可运行字节码版本。

java -version 和 javac -version 输出不一致说明什么
这代表你当前的 Java 运行时(java)和编译器(javac)来自不同 JDK 实例,环境已混装。常见于手动安装多个 JDK 后只更新了 PATH 中的 java,却没同步调整 javac 路径,或系统通过 update-alternatives 注册了不同版本的命令。
典型现象:java -version 显示 17.0.2,javac -version 却返回 11.0.20 —— 此时用 javac 编译出的 class 文件默认目标字节码版本是 11,但运行时却交给 JDK 17 的 JVM 执行,可能触发 java.lang.UnsupportedClassVersionError。
- 必须保证两者主版本号一致(如都是 17),次版本号可略有差异(如 17.0.2 vs 17.0.1),但不能跨大版本
-
javac -version才真正反映你「能写什么语法」:Java 17 的javac支持sealed类、模式匹配等特性;Java 11 的javac不识别它们 -
java -version决定「能跑什么字节码」:JDK 11 JVM 无法加载 JDK 17javac编译出的 class(除非显式加-target 11)
如何确认当前实际生效的 JDK 安装路径
别只信 $JAVA_HOME —— 它可能被设错、未生效,或指向一个只有 JRE 的目录。最可靠的方式是顺藤摸瓜:
- 先执行
which java和which javac,看两个命令是否指向同一bin目录下的不同文件 - 再对每个结果运行
readlink -f $(which java)和readlink -f $(which javac),追踪到真实路径(避免符号链接干扰) - 对比两者父目录的上两级:比如
/usr/lib/jvm/java-17-openjdk-amd64/bin/java和/usr/lib/jvm/java-11-openjdk-amd64/bin/javac就明显不是一套 - 如果
javac找不到,检查$JAVA_HOME/bin下是否存在javac文件;不存在说明你装的是 JRE 包(如java-17-openjdk),而非 JDK 包(如java-17-openjdk-devel)
Linux 发行版中 JDK 包名差异直接影响能否编译
在 openEuler、CentOS、RHEL 等使用 dnf/yum 的系统中,OpenJDK 被拆成多个独立软件包,名字差一个后缀就决定你有没有 javac:
-
java-17-openjdk→ 只含 JRE,提供java、jshell等运行时工具,**不含javac** -
java-17-openjdk-devel→ 完整 JDK,包含javac、javadoc、jar、头文件和静态库 -
java-17-openjdk-headless→ 无图形界面的 JRE,常用于服务器,也不含开发工具 - Debian/Ubuntu 略有不同:
openjdk-17-jrevsopenjdk-17-jdk,后者才带编译器
所以当你 dnf install java-17-openjdk 后发现 javac 不存在,不是安装失败,而是根本没装对包 —— 补一句 dnf install java-17-openjdk-devel 就行。
javac 编译时的 -source/-target 参数容易掩盖版本混乱
即使 javac -version 是 11,你也能用 -source 17 -target 17 强行编译,但会报错:error: Source option 17 is not supported。反过来,若 javac 是 17 版本,默认生成的就是 class 文件版本 61(对应 Java 17),但如果你用 -target 11,它会降级生成版本 51 的字节码,此时就能被 JDK 11 JVM 运行。
- 这个参数只控制输出格式,不改变
javac自身支持的语言特性 ——-source 17才允许写record或switch表达式 - 生产环境建议显式指定
-source和-target,尤其当构建机和运行机 JDK 版本不同时 - Maven 用户注意:
maven-compiler-plugin的source和target配置,最终仍受限于本地javac版本能力
最易被忽略的一点:java -version 和 javac -version 的输出里,厂商标识(如 Temurin、Corretto、Microsoft Build of OpenJDK)可能不同 —— 这意味着你机器上真有多个发行版共存,而不仅仅是版本号不同。











