java -version 不够可靠,因它仅反映 path 中首个 java 可执行文件的版本,不体现 java_home 是否生效、ide 或 ci 是否覆盖配置;真实 jdk 版本须用 readlink -f $(which java)(linux/macos)或 java -xshowsettings:properties -version 验证。

java -version 输出的不一定是你认为的那个版本
很多开发者装完 OpenJDK 后执行 java -version 看到“17.0.2”,就默认当前项目、IDE、CI 都在用这个版本——但实际可能调用的是系统 PATH 里排在前面的另一个 JDK(比如旧版或 JRE),尤其在多版本共存、JAVA_HOME 未设或设错时,这种偏差非常隐蔽。
为什么 java -version 不够可靠
它只反映 PATH 中第一个 java 可执行文件的行为,不体现环境变量配置是否生效、IDE 是否覆盖了系统设置、容器内是否用了镜像自带 JDK。常见误导场景:
- 你刚装了
openjdk-21-jdk,但which java返回的是/usr/bin/java—— 这其实是update-alternatives的符号链接,背后可能是 JDK 11 -
JAVA_HOME指向/usr/lib/jvm/java-21-openjdk-amd64,但PATH里没加$JAVA_HOME/bin,终端仍调用旧版 - IntelliJ 默认用项目 SDK,和终端
java -version完全无关;Maven 构建时读的是MAVEN_OPTS或mvn -v显示的 JDK
readlink -f $(which java) 才是真实路径的金标准
这条命令能穿透所有符号链接,直达 java 二进制文件的实际位置,从而确认它属于哪个 JDK 版本目录。Linux/macOS 下直接运行:
readlink -f $(which java)
输出类似:
/usr/lib/jvm/java-17-openjdk-amd64/bin/java
关键看路径中带版本号的父目录名(这里是 java-17-openjdk-amd64)。Windows 用户可用:
for %i in (java.exe) do @echo %~$PATH:i
再手动查该路径的上两级目录名(如 C:\Program Files\Java\jdk-17.0.2)。
验证 JAVA_HOME 是否真正被进程读取
环境变量只是声明,不一定被当前 shell 或子进程继承。检查三件事:
-
echo $JAVA_HOME—— 确认变量有值且路径存在 -
ls -d $JAVA_HOME/jre 2>/dev/null || echo "no jre subdir"—— OpenJDK 11+ 已移除jre子目录,若存在说明可能是旧版或 Oracle JDK -
java -XshowSettings:properties -version 2>&1 | grep -E "(java.home|java.version)"—— 这个命令强制 JVM 输出它自己认定的java.home和版本,结果最权威
Docker 或 CI 环境下容易忽略的点
容器里 java -version 正常,不代表构建阶段或 Maven 插件用的是同一个 JDK:
-
docker exec -it myapp java -XshowSettings:properties -version 2>&1 | grep java.home—— 必须加-XshowSettings,不能只信echo $JAVA_HOME - GitHub Actions 中,
actions/setup-java设定的 JDK 对run步骤有效,但对uses的第三方 action 可能无效,需显式传参 - Maven 项目若用
maven-compiler-plugin指定了source/target,只控制字节码级别,不约束运行时 JDK 版本
真正决定“实际使用哪个版本”的,永远是进程启动那一刻 java 命令的真实路径,以及 JVM 自己报告的 java.home。别依赖记忆、文档或安装记录——运行时才作数。











