简介JDK 1.8免安装版是一份面向Java开发者与初学者的开箱即用开发环境包解压后无需经过安装向导也不必手动配置环境变量适合快速搭建编译、调试与运行环境或在不便进行系统级安装的机器上临时使用。压缩包共1475个文件约173.74MB以722个jar运行库、228个xml配置、78个dll与74个exe可执行组件为主并包含properties配置、html说明、字体图像及脚本等资源覆盖开发工具、运行时库与辅助说明的主要组成部分目录组织较完整。包内还提供JDK与JavaFX源码压缩包、原生头文件、核心类库和版权许可说明便于读者查阅实现细节、核对授权条款并直接开展程序测试与兼容性验证对希望理解Java内部机制或搭建轻量开发环境的人较有价值。目前已有536人学习下载适合需要快速验证代码、补充JDK8环境或研究Java内部机制的中初级开发者使用。1. JDK 1.8 免安装版一个解压包顶掉安装程序给一批离线内网机器配开发环境最省事的做法往往不是跑安装程序而是把 JDK 1.8 免安装版的压缩包解压到 D 盘改两个环境变量java -version一出结果就完事。所谓 JDK 1.8 免安装版就是把官方 JDK 8 的完整目录树原样打成 zip 或 tar.gz下载可直接使用不写注册表、不往系统盘塞公共运行库、不注册浏览器插件用完删目录就算卸载。它最适合三类人开发机上已经装了高版本 JDK、但老项目必须跑 8 的内网机器没有安装权限、只能拷文件进去的在同一台机器上要并存两三个 JDK 的构建机维护者。下面按「拆包看懂结构—配变量—跑通验证—排错—多版本共存」的顺序把这套东西落到能照着复现的程度。2. 拆包之前先看结构六个目录、三种位数、一套校验很多人拿到压缩包第一反应是双击解压然后直接配 Path配完发现javac找不到、IDE 里识别成 JRE 而不是 JDK、构建脚本报路径不存在。这些问题九成在解压那一步就埋下了跟后面的命令没关系。2.1 绿色包与安装版的行为差异为什么这个差异会反咬一口安装程序干的事其实有四件复制文件、在注册表里写 JavaSoft 相关键值、往系统 Path 追加一项、注册若干附加组件浏览器插件、公共 JRE 副本之类。免安装版只干第一件。这一条差异会在几个地方反咬你第一凡是通过注册表探测 Java 位置的旧工具都看不见这个 JDK。某些老版本安装包、驱动安装器、证书工具会自动去查注册表查不到就提示「未检测到 Java 运行环境」哪怕你java -version跑得好好的。这不是你配错了是对方压根没打算读环境变量。第二Path 完全靠你自己加加的位置决定了谁生效。安装程序习惯把自己那一项塞到 Path 最前面所以你解压版加在末尾时命令行里命中的仍然是安装在系统里的高版本。第三卸载是真干净。删目录、删两条环境变量不留残余。这一点在同时装过三四个 JDK 的机器上很值钱——安装版卸载不干净留下的 javapath 目录是后面一堆「明明卸了还在」问题的源头。第四升级就是换目录改JAVA_HOME。8u 系列的小版本更新把新目录解压出来把变量指过去旧的留着做后悔药出问题两分钟切回去。提示如果你只是自己开发用免安装版唯一要额外注意的是「工具探测」这一类场景。团队里有人写死C:\Program Files\...的脚本换绿色版当天就会挂。2.2 目录逐个数bin、jre、lib、include、db 各自管什么解压出来的顶层目录名一般是jdk1.8.0_XXX里面的结构在各小版本之间基本稳定。下面这张表是我自己整理给同事看的重点在最后一列——哪些东西碰了会出事。目录/文件内容能不能删常见误用binjavac、java、jar、javadoc、javap、keytool、jps、jstack、jmap等可执行文件不能只把jre\bin加进 Path导致有java没javacjre私有运行环境bin\client\jvm.dll、lib\rt.jar、lib\ext不能把JAVA_HOME指到这里编译期直接失效libtools.jar、dt.jar等编译与工具期依赖不能手工删tools.jar后依赖编译器 API 的工具全挂includejni.h等 JNI 头文件不能做本地库编译时忘了带-I%JAVA_HOME%\includedb内置的 Derby 数据库可删但建议留删了之后某些示例工程跑不起来排查半天src.zip标准库源码可删删了 IDE 里点进String只能看反编译release纯文本写着JAVA_VERSION1.8.0_XXX不能版本号说不清时这是最可靠的判据release文件值得单独说一句。同一个 JDK 目录被人拷来拷去、目录名被改成jdk8、java8、jdk之后你没法从名字判断具体是哪个小版本。release里那行JAVA_VERSION是原始值不会被改名影响比java -version更早能看到。接手别人机器时先看这个文件比跑命令快。jre\lib\ext这个目录要提醒一下它会被运行期自动加载很多人图省事把第三方 jar 丢进去结果本机跑得好、换台机器就 NoClassDefFoundError。这类隐式加载是典型的黑匣子别用。2.3 挑包与校验位数、压缩格式、解压路径规范Windows 上分 32 位和 64 位两套包文件名里带i586的是 32 位带x64的是 64 位Linux 上一般是tar.gz。位数选错不会报错只会让你在跑大内存应用时看到Invalid maximum heap size或者堆上限卡在 1.5G 左右上不去。判断当前跑的是哪个位数的 JDK最直接的办法是看java -version那三行末尾有没有64-Bit。压缩包到手先校验尤其是从内部文件服务器、U 盘、聊天工具里传过几手的包。丢字节的 zip 往往能解压出大半文件bin目录看起来是全的等到用时才发现某个 dll 损坏。# Windows计算 SHA256跟发布方给出的值逐字符比对 certutil -hashfile .\jdk1.8.0_XXX.zip SHA256 # Windows 10 1803 之后自带 tar也可以直接解压 zip tar -xf .\jdk1.8.0_XXX.zip -C D:\dev\jdk# Linux校验后解压到统一目录 sha256sum jdk-8uXXX-linux-x64.tar.gz sudo mkdir -p /opt/jdk sudo tar -xzf jdk-8uXXX-linux-x64.tar.gz -C /opt/jdk第一条命令只做校验不做修改certutil输出的哈希带空格分行比对时把空格去掉。第二条用系统自带tar解压-C指定目标目录比右键解压更可控——不少第三方解压软件在处理深目录时会截断路径或者在长文件名上悄悄改名解压完bin里少几个文件都看不出来。路径规范只有一句话不要有空格不要有中文层级尽量浅。D:\dev\jdk\jdk1.8.0_XXX是标准答案C:\Users\某某\Desktop\新建文件夹\jdk是灾难现场。空格和中文在命令行里能靠引号绕过去但一旦进入构建脚本、批处理、某些老工具的启动器引号处理就开始翻车报的错还往往是CreateProcess error2这种完全指不到病灶的。提示解压后先别急着配环境变量直接进bin目录在当前目录下跑一次.\java -version。这一步能排除掉压缩包损坏和位数选错两个问题成本十秒。3. 环境变量落地JAVA_HOME 的正确取值与两套系统写法环境变量配错是 JDK 8 落地环节最高频的翻车点而且症状极其分散有人表现为javac找不到有人表现为 IDE 里没有源码有人表现为构建工具用了另一个版本。根因都能追到同一个地方——JAVA_HOME到底该指向哪一级。3.1 JAVA_HOME 的三个候选值只有第一个能活新手最容易在三个值之间犹豫D:\dev\jdk\jdk1.8.0_XXXJDK 根目录D:\dev\jdk\jdk1.8.0_XXX\binD:\dev\jdk\jdk1.8.0_XXX\jre正确答案只有第一个。原因不在于约定俗成而在于绝大多数工具读取JAVA_HOME之后会自己拼后缀构建工具的启动脚本拼\bin\javaWeb 容器拼\bin\javac或者直接读\lib\tools.jar。你把JAVA_HOME设成bin人家拼出来就是...\bin\bin\java报错信息里那串重复的bin就是最明显的线索。你把JAVA_HOME设成jrejava能跑因为jre\bin里确实有java.exe但javac.exe只在 JDK 的bin里编译环节必然崩而且崩得很有迷惑性——运行时一切正常。然后 Path 里加的是%JAVA_HOME%\binWindows或$JAVA_HOME/binLinux/macOS。这里再强调一遍是bin不是jre\bin。一个快速的自我检查方式配完后执行echo %JAVA_HOME%和where javaWindows/which -a javaLinux看输出的第一条路径是不是%JAVA_HOME%\bin\java.exe。如果命中的是别处的 java说明 Path 顺序有问题不是变量值有问题。3.2 Windows 三种配法图形界面、setx 与切换脚本图形界面此电脑右键 → 属性 → 高级系统设置 → 环境变量。新建系统变量JAVA_HOME值为 JDK 根目录在系统变量Path里新增一项%JAVA_HOME%\bin并用右侧「上移」把它挪到靠前位置。这是最稳的方式因为它会把%JAVA_HOME%\bin以字面量形式存进注册表切换版本时改一个变量就够。setx 命令行:: 需要管理员权限的窗口执行/M 表示写系统变量 setx JAVA_HOME D:\dev\jdk\jdk1.8.0_XXX /M :: 验证 reg query HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment /v JAVA_HOMEsetx有两条硬限制必须知道。一是值长度上限 1024 字符超了会被静默截断二是它写入后不影响已经打开的窗口当前 cmd 里echo %JAVA_HOME%仍然是旧值必须新开窗口某些情况下还要重启资源管理器才能让新进程继承到。还有一条是血泪经验不要用setx去改 Path。:: 反面教材别这么干 setx PATH %JAVA_HOME%\bin;%PATH% /M这条命令里的%PATH%在脚本执行时就被展开成了当前系统 Path 和用户 Path 拼起来的完整字符串然后作为一个普通字符串写回去。后果是用户 Path 里原本的%JAVA_HOME%\bin这种字面量被固化成具体路径系统 Path 的内容被复制进用户 Path以后再装任何软件追加 Path 都会撞车Path 越滚越长最后撞上长度上限。想改 Path回图形界面手动加或者用reg add配合REG_EXPAND_SZ类型小心处理别图省事。切换脚本机器上同时有 8 和 17 的时候做一个批处理比每次开图形界面快得多。echo off :: jdk-switch.bat 用法jdk-switch 8 / jdk-switch 17 setlocal set JDK8D:\dev\jdk\jdk1.8.0_XXX set JDK17D:\dev\jdk\jdk-17.0.9 if /i %18 ( set TARGET%JDK8% ) else ( if /i %117 ( set TARGET%JDK17% ) else ( echo usage: jdk-switch 8 ^| 17 exit /b 1 )) :: 只改 JAVA_HOMEPath 里保留 %JAVA_HOME%\bin 字面量 setx JAVA_HOME %TARGET% /M echo 已切换到 %TARGET% echo 请新开一个命令行窗口验证 java -version endlocal逻辑很直白setlocal隔离变量作用域避免污染调用者环境两个候选路径写死参数匹配失败的走exit /b 1返回非零码方便脚本串联。参数说明%1是第一个位置参数/i让字符串比较忽略大小写/M写系统级变量。注意脚本只改JAVA_HOMEPath 里那一项保持字面量不变这样切换才是一次操作。脚本打印的提示不是客套——当前窗口的JAVA_HOME确实没变必须新开窗口。3.3 Linux 与 macOSprofile.d、alternatives、shell rcLinux 上分两种场景。全局生效写/etc/profile.d/下新建一个.sh登录时自动 source只对自己生效写~/.bashrc或~/.zshrc。# 全局生效文件名随意必须是 .sh 结尾权限 644 sudo tee /etc/profile.d/jdk8.sh /dev/null EOF export JAVA_HOME/opt/jdk/jdk1.8.0_XXX export PATH$JAVA_HOME/bin:$PATH EOF sudo chmod 644 /etc/profile.d/jdk8.sh source /etc/profile.d/jdk8.sh java -version关键点有三个export PATH里$JAVA_HOME/bin必须排在$PATH前面否则系统自带的/usr/bin/java抢先here-doc 用了带引号的EOF这样$JAVA_HOME不会被当前 shell 提前展开写进文件的是字面量chmod 644是因为有些发行版对profile.d的权限敏感权限不对会被跳过且不报错。执行source只影响当前 shell新开的终端会自动带上。这个写法比直接改/etc/profile好的地方是卸载时删掉一个文件就行不会在一堆历史改动里找自己加的那两行。如果机器上已经有多个 JDK 且有包管理器在管用alternatives更合适它维护的是/usr/bin/java这个软链# 注册两个候选最后的数字是优先级越大越优先 sudo update-alternatives --install /usr/bin/java java /opt/jdk/jdk1.8.0_XXX/bin/java 1081 sudo update-alternatives --install /usr/bin/javac javac /opt/jdk/jdk1.8.0_XXX/bin/javac 1081 # 交互式切换 sudo update-alternatives --config java注意java和javac要分别注册只注册java是最常见的半吊子配置运行期是 8编译期可能还是 17混出来的 class 文件版本号对不上报UnsupportedClassVersionError。macOS 上多数人用~/.zshrcexport JAVA_HOME$(/usr/libexec/java_home -v 1.8) export PATH$JAVA_HOME/bin:$PATH/usr/libexec/java_home会在标准位置里找匹配的 JDK但免安装版通常不在标准位置所以更稳的做法还是直接写死绝对路径。如果非要让它被识别可以在~/Library/Java/JavaVirtualMachines/下建一个指向解压目录的软链这个目录是系统约定的 JDK 存放位置。4. 从 java -version 到跑通第一段代码验证链路怎么搭配完变量只跑一条java -version就宣布成功是后面一半问题的来源。验证要分层做每一层确认一件事。4.1 三条命令验证层次别只看第一行# 1. 运行期版本 java -version # 2. 编译期版本这条才是 javac 在不在的判据 javac -version # 3. 实际命中的可执行文件路径 where java # Windows where javac which -a java # Linux / macOSjava -version输出到标准错误而不是标准输出写脚本重定向时要注意java -version 21否则拿到空文件。输出三行第一行是版本号第二行是构建号末尾有64-Bit说明位数正确。javac -version是最容易被跳过的一条。java存在不代表javac存在——jre\bin里就有java.exe。这两条版本号必须一致不一致说明 Path 里混进了两个不同来源的 JDK后面编译运行一定出事。where java/which -a java列出的是 Path 顺序命中的所有候选。看第一条是不是你刚配的目录如果第一条是C:\Program Files\Common Files\...\javapath\java.exe这种说明安装版残留还在抢占需要把它从 Path 里挪走或者下调顺序。Linux 上which -a会列出全部命中项比which更有诊断价值。4.2 编译运行示例顺手把编码参数定死验证程序别写Hello World信息量太小。用下面这段把版本、路径、编码、参数四件事一次性打出来。public class EnvCheck { public static void main(String[] args) { System.out.println(java.version System.getProperty(java.version)); System.out.println(java.home System.getProperty(java.home)); System.out.println(java.vendor System.getProperty(java.vendor)); System.out.println(os.arch System.getProperty(os.arch)); System.out.println(file.encoding System.getProperty(file.encoding)); System.out.println(sun.jnu.encoding System.getProperty(sun.jnu.encoding)); System.out.println(args String.join(|, args)); System.out.println(中文输出测试你好JDK 8); } }编译和运行分两条命令别用一条龙# 编译-encoding 指定源文件的字符编码必须跟你编辑器保存的编码一致 javac -encoding UTF-8 -d out EnvCheck.java # 运行-cp 指定类路径-D 指定运行时属性 java -Dfile.encodingUTF-8 -cp out EnvCheck alpha betajavac那行-encoding UTF-8告诉编译器源文件是 UTF-8。如果你在中文 Windows 上用记事本或某些编辑器保存成了 GBK而这里写 UTF-8报错是「编码 GBK 的不可映射字符」或者编译过了但字符串乱码。-d out把 class 文件输出到out目录源码目录保持干净——顺手养成这个习惯后面接构建工具时不会因为源码目录里混着 class 文件而困惑。java那行-Dfile.encodingUTF-8设置 JVM 的默认字符集。JDK 8 在中文 Windows 上file.encoding默认是 GBK而sun.jnu.encoding又是另一套管文件名编码这两个不一致是文件读写乱码的经典来源。上面那段代码把两个都打出来一比就知道。alpha beta是传给main的参数用来确认参数传递没被 shell 吃掉。跑完的输出里java.home应该是...\jdk1.8.0_XXX\jre注意它指向的是jre子目录而不是 JDK 根目录这是正常的——java.home表示运行时环境位置跟JAVA_HOME不是一回事。很多人看到这里以为配错了其实没错。4.3 IDE 与构建工具的四处对齐命令行通了IDE 里照样可能用的是另一个 JDK。某 IDE 对 JDK 的引用至少有三个独立位置加上构建工具自己的一份一共四处要核对。配置位置典型项该设成什么不对齐的症状项目 SDKProject SDK / JDKJDK 8 根目录代码提示按高版本语法给编译报错模块语言级别Language Level8用了 9 语法写代码编译期才炸运行配置JRE / 运行环境与项目 SDK 一致编译用 8运行用 17报类版本不兼容构建工具编译插件 source/target1.8产物 class 版本号是 52 之外的值构建工具那一项最容易被忽略。以主流构建工具的编译插件为例source和target都得显式写 1.8否则它会跟随当前JAVA_HOME的版本走——今天切到 17 构建一次产物就是 class 版本 61扔到只有 JDK 8 的服务器上直接UnsupportedClassVersionError。另外要注意release这个参数是 JDK 9 之后javac才支持的在 JDK 8 环境下配release会直接报参数不识别老老实实用source/target。还有tools.jar。JDK 8 里编译器 API 在lib\tools.jar中不在标准运行时里。如果你的代码里用了javax.tools.JavaCompiler做动态编译运行时的 classpath 必须显式带上它否则ClassNotFoundException会在运行时才出现编译期一点提示都没有。提示接完 IDE 之后回到命令行再跑一次javac -version和java -version。IDE 的配置只影响 IDE 自己不影响系统 Path两边都通了才算真通。5. 排查记录五条把 JDK 8 配翻车的坑与解法这一节按「现象 → 原因 → 解决」写都是我在自己机器和同事机器上反复见过的。5.1 现象java 能跑javac 提示不是内部或外部命令原因几乎固定Path 里加的是%JAVA_HOME%\jre\bin或者干脆加的是jre\bin的绝对路径。jre\bin里只有运行时相关可执行文件javac.exe、jar.exe、javadoc.exe全在 JDK 的bin下。因为java命令能用很多人就默认配好了直到要编译才炸。解决把 Path 里那一项改成%JAVA_HOME%\bin删掉jre\bin那项新开窗口后用where javac确认。顺带检查JAVA_HOME本身有没有指到jre目录——指到jre的话即使 Path 写的是%JAVA_HOME%\bin拼出来也是jre\bin症状一模一样。5.2 现象改完环境变量新开的窗口里版本还是旧的原因有三个层次要按顺序排。第一层setx之后没有新开窗口当前进程继承的还是旧环境块这个最常见也最容易被忽略。第二层Windows 上系统 Path 和用户 Path 是按「系统在前、用户在后」拼接的你把 JDK 8 加在用户 Path 末尾而系统 Path 前面还有安装版留下的 javapath 目录命中的自然是旧的。第三层某些进程资源管理器启动的 cmd、被 IDE 拉起来的终端继承的是资源管理器在登录时拿到的环境快照改了系统变量它也不刷新。解决先where java看命中路径确认问题在第几层。停在第一层的关掉所有终端重开。停在第二层的用echo %PATH%把顺序打出来把%JAVA_HOME%\bin上移到系统 Path 最前。停在第三层的任务管理器里重启资源管理器或者干脆注销重登。这套排查顺序建议记牢不然很容易陷入「改了没生效—再改—还是没生效」的玄学循环。5.3 现象解压到桌面或「下载」目录后构建脚本报 CreateProcess error2原因路径里有空格C:\Users\XXX\Desktop还好C:\Program Files和带空格的用户名就麻烦了或中文甚至同时有。命令行里空格靠引号能解决但构建脚本在拼命令行时漏了引号或者把参数拆成了两段操作系统就找不到那个可执行文件。中文路径的问题更隐蔽取决于sun.jnu.encoding和系统区域设置同一份脚本在不同机器上表现不同。解决把 JDK 挪到无空格无中文的浅层路径比如D:\dev\jdk\jdk1.8.0_XXX。挪完记得改JAVA_HOME因为它是绝对路径不会跟着走。这条也是我建议所有解压类资源都遵守的规范工具链的安装位置不要放在用户目录和系统目录下面。5.4 现象换到免安装版之后某些老工具说检测不到 Java原因这些工具通过注册表探测 Java 位置而绿色包不写注册表。它们不读JAVA_HOME也不读Path只看HKLM\SOFTWARE\JavaSoft\Java Runtime Environment或Java Development Kit下面那套键值。解决优先找工具自身的配置项。多数工具支持手动指定 Java 路径改成绝对路径最干净。如果工具完全不给你配的入口有两种权宜之计一是把免安装版目录整体复制一份到安装版的默认位置让工具的固定路径能找到二是手工在注册表里补一份键值指向解压目录。第二种我不太推荐在共享机器上做因为注册表是个黑匣子写进去之后没人记得是谁写的、什么时候写的出问题时排查成本极高。真要用写之前先导出备份这一点别省。5.5 现象多版本共存之后构建机随机用错版本原因构建机上有全局JAVA_HOME、有 CI 配置里的 JDK 指定、有 IDE 自带的 JDK 快照、还有构建工具缓存里记录的编译期 JDK四套来源互相覆盖。表现出来就是同一份代码今天构建成功、明天失败或者两台构建机产物不一致。这类问题排查起来很折磨人因为日志里只会告诉你编译目标版本不对不会告诉你 JDK 是从哪来的。解决定一条硬规则——构建脚本只用显式路径不依赖全局环境变量。启动脚本第一行就set JAVA_HOMED:\dev\jdk\jdk1.8.0_XXX或者export JAVA_HOME/opt/jdk/jdk1.8.0_XXX覆盖掉继承来的值。构建工具缓存里记录的 JDK 也要在分支切换后清一次。同时把所有机器上的 JDK 目录按统一规范命名并放在统一位置这样人眼扫一遍就能发现异常。6. 多版本共存与一键切换把 JDK 8 做成可插拔底座真正把绿色版价值榨出来的场景是多版本共存。我习惯在D:\dev\jdkLinux 下是/opt/jdk下把所有版本平铺排开目录名带上版本号不许改。目录版本典型用途切换方式jdk1.8.0_XXX8老项目编译、旧依赖的运行时改JAVA_HOMEjdk-11.0.X11过渡期项目改JAVA_HOMEjdk-17.0.X17新项目改JAVA_HOME平铺的好处是路径可预测切换脚本里直接拼目录名就行不用去各个软件的私有目录里翻。版本号保留在目录名里是一种低成本的文档——半年后回来看到一堆jdk8、jdk8-copy、jdk8-new才知道什么叫痛苦。Linux 上的切换函数写在 shell rc 文件里比单独的脚本好用因为函数在当前 shell 内执行export能生效# 追加到 ~/.bashrc 或 ~/.zshrc 末尾 export JDK8_HOME/opt/jdk/jdk1.8.0_XXX export JDK11_HOME/opt/jdk/jdk-11.0.X export JDK17_HOME/opt/jdk/jdk-17.0.X jdk() { case $1 in 8) export JAVA_HOME$JDK8_HOME ;; 11) export JAVA_HOME$JDK11_HOME ;; 17) export JAVA_HOME$JDK17_HOME ;; *) echo usage: jdk 8|11|17; return 1 ;; esac # 先剔除 PATH 中所有历史 JDK 条目再前置当前版本避免反复切换导致无限增长 PATH$(printf %s $PATH | tr : \n | grep -v /opt/jdk/ | paste -sd :) export PATH$JAVA_HOME/bin:$PATH echo JAVA_HOME - $JAVA_HOME java -version 21 | head -n 1 }这段的关键在中间那行 PATH 处理。如果直接写export PATH$JAVA_HOME/bin:$PATH每切一次就多一条切二十次之后 PATH 长得没法看而且旧版本还留在里面一旦当前版本目录被删就会命中残留路径。先用tr把冒号分隔转成行、grep -v过滤掉所有 JDK 目录、paste拼回去保证任何时刻 PATH 里 JDK 条目最多一条。case里参数不匹配时return 1而不是exit 1因为这是在当前 shell 里执行函数用exit会把终端关掉。最后那行java -version 21 | head -n 1是即时回显切完立刻能看见结果不用再敲一遍命令——这一步看着小实际上省掉了很多「以为切了其实没切」的误判。切换完成后还有一个容易漏的验证动作跑一次javac -version和一段带中文输出的编译运行。java通了不代表javac跟着变了尤其在某些 shell 里JAVA_HOME改了但PATH里的顺序没跟上。我现在每次切完版本都会顺手跑一遍java -version javac -version echo $JAVA_HOME三行输出对着看。从那以后我给自己定了条规矩任何一台机器上装 JDK无论是安装版还是免安装版配完变量必须走一遍完整验证链——java -version、javac -version、where/which -a看命中路径、编译一个带中文输出的类、再在 IDE 里跑一次。少走一步后面就得多花半小时找那个不一致的地方。这套流程跑熟了不到一分钟比任何事后排查都划算。希望帮到你。本文还有配套的精品资源点击获取