JDK21安装教程:Windows/macOS/Linux环境变量配置步骤
作者:何为自律
JDK21 大概是近两年 Java 生态里含金量最高的一次 LTS 版本了。从 2023 年 9 月发布到现在,越来越多团队把开发环境从 JDK8、JDK11 往 JDK21 迁移,核心原因就三个字:虚拟线程。这东西对高并发服务的开发体验提升是非常直观的,再加上记录模式、switch 模式匹配、分代 ZGC 这些特性,等于把之前要引入额外框架才能做到的能力直接下沉到 JDK 层。不过新版本带来的第一个门槛反而不是语法和 API,而是怎么把 JDK21 在 Windows、macOS、Linux 上正确装好,并把环境变量配明白。这篇文章是我在三个平台反复安装、卸载、切换版本时踩坑后的完整整理,适合刚入门需要搭环境的新手,也适合要在一台机器上管理 JDK8、11、17、21 多个版本的老手。
这里先说明一点,我推荐把 JDK 安装和项目用的 JDK 版本分开理解:安装解决的是“机器上有什么”,环境配置解决的是“默认命令用哪个”,而多版本切换解决的是“不同项目各用各的”。这三件事很容易混在一起,导致新手装了新版却还是跑到旧版,本文会把这三条线分别讲透。
1. 整体思路:装 JDK21 之前先想清楚的三件事
1.1 JDK21 是什么,为什么它值得你现在就换
JDK21 是 Java 生态里的一个长期支持版本,按照 Oracle 的发布节奏,每两年会出一个 LTS 版本,JDK21 之前的上一个 LTS 是 JDK17,再往前是 JDK11 和 JDK8。长期支持意味着 Oracle 会持续提供多年更新,不只是功能特性层面的小修小补,还包括安全补丁和生产环境真正需要的稳定性保障。所以如果你的项目还在用 JDK8 或 JDK11,从版本生命周期角度来说,JDK21 是目前最值得升级的下一个目标。
JDK21 带来的核心变化是虚拟线程,也就是 JEP 444。传统 Java 的并发模型里,一个请求通常对应一个平台线程,线程数量上去之后,上下文切换和内存占用都会成为瓶颈。虚拟线程则是由 JVM 管理的轻量级线程,数量可以开到几十万甚至上百万,很多需要手写异步回调或者使用响应式框架的场景,可以退回最简单的同步阻塞写法,性能和可维护性反而更好。这一点直接改变了服务端编程的架构选型。
除此之外,JDK21 还完善了 switch 模式匹配和记录模式,让多态数据处理代码变得非常简洁;分代 ZGC 降低了垃圾回收的停顿时间,对大堆内存应用是实打实的红利。从一个资深开发者的角度,我的判断是:新项目直接上 JDK21,老项目也值得在下一个迭代周期把升级纳入计划,而不是继续观望到 JDK25。
1.2 发行版选择:Oracle、Temurin、Corretto 到底该选哪个
不少人在安装 JDK 时第一个困惑是:我去哪里下载?Oracle 官网下载的是 Oracle JDK,Adoptium 下载的是 Eclipse Temurin,还有 AWS 维护的 Corretto、微软的 Microsoft Build of OpenJDK、Azul 的 Zulu,这些都属于 OpenJDK 系的发行版,底层共享同一套 JDK 源码,只是由不同组织做了构建、测试和分发。功能层面差别很小,真正影响选择的是协议、更新策略和平台支持。
Oracle JDK 在 JDK17 之后调整了许可协议,个人开发、开发和测试环境下可以免费使用,但生产环境需要确认是否满足 Oracle 的 No-Fee Terms and Conditions。如果你所在的公司已经购买了 Oracle 的支持服务,又或者你只是个人学习,那直接用 Oracle JDK 没有问题,不过要把“免费使用场景”和“商业支持场景”分清楚。
Eclipse Temurin 是 Adoptium 社区构建的高质量发行版,完全开源免费,商业使用也没有限制。我个人的建议是:大多数开发者,尤其是拿不准协议、想省心长期用的人,直接选 Temurin。它提供了 Windows 下的 zip 和 msi、macOS 下的 pkg 和 tar.gz、Linux 下的 tar.gz、deb 和 rpm,覆盖非常全,还默认带 JavaFX 运行时,桌面开发也更方便。
Amazon Corretto 和 Microsoft Build of OpenJDK 则更适合已经在 AWS 或 Azure 生态里的团队,它们的补丁更新节奏跟着云厂商的运维周期走,部署上更契合。本文下面的实操部分会以 Temurin 和 Oracle JDK 为主,发版差别不影响配置方法,你换成其他发行版,环境变量配置思路完全一样。
1.3 三平台安装策略对比:包管理器、安装包、压缩包哪个适合你
三平台装 JDK21 的方式可以归成三类:官方原生安装包、压缩包解压、包管理器命令。原生安装包包括 Windows 的 exe/msi、macOS 的 dmg/pkg,优点是图形化向导,适合第一次接触 JDK 安装的用户,缺点是安装器可能会往系统目录和注册表里写东西,后续清理不方便。
压缩包解压是把 tar.gz 或 zip 解压到某个目录,手动配环境变量,这种方式最透明,装在哪、删不删、怎么切换全由你自己掌控,也是服务器部署最常用的方式。包管理器则是压轴推荐,Windows 有 winget,macOS 有 Homebrew,Linux 有 apt、dnf、yum,一条命令装好装完,路径虽然固定但无脑省心。
我个人在开发机上的习惯是:能用包管理器就用包管理器,因为升级容易;在服务器上则用压缩包解压到 /opt 目录并建立软链接,因为统一管理多版本时更可控。下面三章会分别针对 Windows、macOS、Linux 给出完整路线,你按照自己所在的平台挑对应的章节看即可。
2. 环境准备与前置检查:装之前先花五分钟摸清家底
2.1 JDK21 的系统要求与兼容性说明
JDK21 对系统的最低要求其实并不高:Windows 10 及以上、macOS 11 及以上、Linux 主流发行版都可以跑。内存建议至少 4GB,JDK 本身运行时 256MB 就能启动,但配合 IDE 和构建工具,建议开发机 8GB 起步,这个门槛基本没有淘汰现有硬件。
需要注意两点。第一,Linux 发行版版本跨度比较大,Ubuntu 22.04 的官方软件源默认带的 OpenJDK 最高到 17,24.04 开始才自带 OpenJDK 21,所以用老版本系统的朋友最好从发行版官网或 Adoptium 仓库安装,不要死磕系统和软件源。第二,CentOS 7 这些老系统如果 glibc 版本偏低,可能会遇到部分 JDK 发行版启动报错,这种时候优先选官方为老系统构建的版本,或者直接升级发行版。
架构上也要留意,Apple Silicon 的 Mac 需要下载 aarch64 版 JDK,Intel Mac 用 x64 版,Linux 服务器同理,下错架构的包在启动时会出现 Bad CPU type 或段错误,很容易误判为 JDK 本身有问题。
2.2 检查本机已有的 JDK:避免多版本装完就打架
不少人在装 JDK21 之前,机器上其实已经有 JDK8、JDK11 或 JDK17,不提前搞清楚容易引发两个问题:一是 java -version 一直显示旧版本,以为自己装失败了;二是 javac 版本和 java 版本不一致,编译产物在运行时莫名其妙出问题。所以无论哪个平台,安装前建议先把本机现状摸清楚。
Windows 下打开 CMD 或 PowerShell,依次执行:
java -version javac -version where java echo %JAVA_HOME%
macOS 和 Linux 下终端里执行:
java -version javac -version which java echo $JAVA_HOME
把输出结果记下来,重点关注三件事:当前默认 JDK 是哪个版本,安装路径在哪里,是通过安装器装的还是解压装的。安装器装的一般有对应卸载程序,解压装的手动删目录即可,如果既有安装器又有解压目录,建议先把旧版本清理干净,再装 JDK21,避免 PATH 里同时出现多条指向不同版本的 java 命令。
2.3 统一规划安装路径:把踩坑概率降到最低
JDK 对安装路径没有硬性要求,但从实际维护角度,我强烈建议统一目录规则。Windows 上推荐 C:\Java\jdk-21 这种纯英文无空格、无中文、无特殊符号的路径,避免某些老式构建脚本和工具因为路径解析出问题。macOS 和 Linux 上推荐 /opt/jdk-21 或 /usr/local/jdk-21,放在系统级目录下权限清晰,多个用户都能用。
也许你会觉得路径要求有点多虑,我在实际项目中真的见过 Jenkins 脚本因为 Windows 路径带空格把 JAVA_HOME 截断导致构建失败的案例。统一路径的另一个好处是备份和切换方便,想用 JDK17 就再解压一个 jdk-17 目录,改一下 JAVA_HOME 指向,旧目录不影响新目录,这种干净的组织方式在出事的时候能省下大量排查时间。
路径规划完成之后,还有一个重要的习惯:环境变量的值尽量指向 JAVA_HOME,而不是直接写死完整路径。Windows 用 %JAVA_HOME%\bin,macOS 和 Linux 用 $JAVA_HOME/bin,这样以后换版本只需要改一个变量,不用维护多处 PATH 配置。
3. Windows 平台下载安装与环境配置全程实录
3.1 Windows 下载 JDK21:三种方式哪种最靠谱
Windows 下载 JDK21 我推荐三种方式,按省心程度排序。第一种是用 winget 命令安装 Temurin 发行版,这是 Windows 11 和较新版本 Windows 10 内置的包管理器,打开 PowerShell 执行:
winget install EclipseAdoptium.Temurin.21.JDK
它会自动下载认可的安装包并执行安装,整个过程不需要手动点向导,后续升级也能走 winget 统一管理,windows 用户如果之前没试过推荐第一次就试这个。
第二种是从 Temurin 官网或者 Oracle 官网下载安装包。Temurin 官网选择 Windows 平台的 msi 安装包,Oracle 官网选择 exe 或 msi,双击进入安装向导,勾选同意协议、选择安装路径即可。这个方式的优势是路径可视化,适合新手,但装完要注意安装器可能往系统 PATH 里写额外内容。
第三种是下载 zip 压缩包解压到指定目录,Temurin 和 Oracle 都提供 zip 格式。这个方式最适合想要完全控制安装内容的人,不需要管理权限,卸载就是删目录,多版本切换时尤其好用。官网页面会提供版本号和 hash 校验值,下载完可以用 sha256sum 校验一下文件完整性,避免传输过程损坏。
3.2 Windows 环境变量配置:JAVA_HOME 和 PATH 一步一步配
Windows 下安装完成后,最关键的一步是把 JAVA_HOME 和 PATH 配好。无论你用的是 msi、exe 还是 zip,这一步都不能少,因为虽然部分安装器会自动配置路径,但自动配置经常和你手动指定的安装路径对不上,而且后续要加其他版本时更容易出问题。
具体步骤:右键“此电脑”或“我的电脑”,选择“属性”,进入“高级系统设置”,点击“环境变量”。在弹出的窗口中,如果只想给自己用,就操作上方“用户变量”;如果想所有用户都能用,就操作下方“系统变量”,但系统变量需要管理员权限。先在“用户变量”区域点击“新建”,变量名填 JAVA_HOME,变量值填你的 JDK21 安装路径,例如 C:\Java\jdk-21。
接着在“系统变量”或“用户变量”里找到 Path 这个变量,双击打开编辑窗口,点击“新建”,输入 %JAVA_HOME%\bin,然后点击“上移”把它移动到列表最上方。这一步非常关键,因为 Windows 在解析命令时是从 PATH 中从上到下按顺序查找的,如果 Path 列表里还有其他 JDK 的 bin 目录,而且排在 %JAVA_HOME%\bin 前面,java -version 就会找到别的版本,表现就是你配置半天还在跑旧版。
另外一个常见的坑是 Oracle 安装器会在 PATH 里加入一条指向 C:\Program Files\Common Files\Oracle\Java\javapath 的内容,这个目录里有一个 java.exe,它指向的是安装器当时安装的版本。如果你以前装过 Oracle JDK 又手动装了新的 JDK21,这条旧路径必须移到 %JAVA_HOME%\bin 下面,或者直接删掉。很多人装完新版后 java -version 还是旧版,八成就是它作祟。
配置完成后,重新打开一个 CMD 窗口(注意是重新打开,已经在跑的命令行不会刷新环境变量),执行:
java -version javac -version echo %JAVA_HOME%
正常显示类似 java version "21.0.1" 以及对应的 javac 版本,说明配置成功。这里还要提醒一句:如果你用的是 PowerShell,可以直接执行 $env:JAVA_HOME 来验证当前环境的变量值。
有的朋友会遇到新开 CMD 仍然读取不到变量的问题,这种情况多半是系统变量和用户变量的优先级问题,或者你修改的是用户变量但用户 PATH 被系统 PATH 覆盖了。最保守的做法是把 JAVA_HOME 配在用户变量,把 %JAVA_HOME%\bin 加到用户 Path 的最前边,重新登录 Windows 后再试,绝大部分问题都能解决。
4. macOS 平台下载安装与环境配置全程实操
4.1 Homebrew 一键安装:最省心的 macOS 方案
macOS 上我首推 Homebrew 安装 JDK21,原因只有一个:后续升级、切换、清理都极其省心。前提是你已经装好了 Homebrew,如果没有装,先去官网按提示安装,安装完执行:
brew install openjdk@21
装完后 Homebrew 会给出提示,大意是 openjdk@21 是 keg-only 的,也就是说它不会自动把 java 命令放进系统 PATH,需要手动配置。这也是很多人装完 brew install 却找不到 java 命令的原因,不是没装成功,而是 Homebrew 默认不会覆盖系统自带的 java 命令优先级。
接下来需要做两步。第一步找到安装路径,执行:
brew info openjdk@21
输出里会给出类似 /opt/homebrew/opt/openjdk@21 的路径,注意 Apple Silicon 芯片的 Mac 是 /opt/homebrew,Intel 芯片的是 /usr/local,路径前缀不同。第二步配置 shell 环境变量,macOS 默认 shell 是 zsh,编辑用户目录下的 ~/.zshrc,在末尾追加:
export JAVA_HOME=$(/usr/libexec/java_home -v 21) export PATH=$JAVA_HOME/bin:$PATH
保存后执行 source ~/.zshrc 或重新打开终端,然后验证 java -version。这里我特意用了 java_home 这个 macOS 系统自带的命令来动态获取 JDK21 的路径,而不是写死 /opt/homebrew/opt/openjdk@21,好处是 macOS 上安装多个 JDK 时,java_home 会自动帮你找到对应版本,切换起来很顺。
如果你希望其他 IDE 和系统工具也能直接识别这个 JDK,可以再执行:
sudo ln -sfn /opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-21.jdk
这样 JDK21 就会被注册到 macOS 的 JavaVirtualMachines 目录下,/usr/libexec/java_home -v 21 就能直接找到它。
4.2 dmg 安装包方式:适合不折腾的直接点按方案
如果你对命令行不够熟悉,或者不愿意碰 Homebrew,macOS 的 Oracle JDK 官方 dmg 安装包是另一个选择。从 Oracle 官网下载对应架构的 dmg 文件后双击打开,里面是标准的苹果安装包向导,一路继续即可,安装器会把 JDK 安装到 /Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home 这个系统目录,并自动配置 /usr/bin/java 的符号链接。
dmg 安装完成后的第一件事是在终端验证:
java -version /usr/libexec/java_home -v 21
第一条命令显示 JDK21 就说明系统默认 java 命令指向没问题,第二条命令显示 JDK21 的路径,说明其他工具能通过 java_home 找到它。这种安装方式有一个特点:JPackage 和大多数 GUI 工具都能自动识别,因为系统目录注册机制已经帮你处理好了,不需要手动改任何配置文件。
想要在不影响系统默认版本的前提下使用 JDK21,可以在 ~/.zshrc 里加上 export JAVA_HOME=$(/usr/libexec/java_home -v 21),并让 PATH 以 $JAVA_HOME/bin 开头。其实即使是 dmg 安装,我也推荐手动加这个 JAVA_HOME 变量,因为一些构建工具和 IDE 对 JAVA_HOME 的依赖比想象中强得多,你不设置,它们就会去猜测路径,白白增加不必要的麻烦。
macOS 上多版本管理还有一个小技巧:终端执行 /usr/libexec/java_home -V 会列出当前机器上所有已注册的 JDK,看看输出路径你就能知道哪些版本存在、顺序如何,配合 JAVA_HOME 的 java_home 命令,基本能做到按项目指定版本。
4.3 macOS 安装后的版本冲突:命令行和 IDE 各说各话怎么破
macOS 上有一种很常见的情况:终端里 java -version 是 JDK21,但打开 IntelliJ IDEA 或 VSCode 之后,IDE 提示找不到 JDK,或者用的还是旧版本。原因是终端的环境变量来源于 ~/.zshrc,而图形化应用在 macOS 上默认不读取 shell 的配置文件,它们直接通过 /usr/libexec/java_home 去查找系统注册的 JDK。
所以在 macOS 上我一般建议两条腿走路:终端类的工具跟 JAVA_HOME 走,GUI 类的工具跟 /Library/Java/JavaVirtualMachines 里注册的版本走。如果你想让 GUI 工具也用 JDK21,要么在 IDE 的项目 SDK 里手动指向 /opt/homebrew/opt/openjdk@21 或 /Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home,要么执行上面说的软链接注册命令,把 JDK 注册进系统目录。
另一个真实的坑是:使用 dmg 安装的旧版本 Oracle JDK 会在 /Library/Java/JavaVirtualMachines 里留下旧目录,JDK21 装好后系统默认 java 可能还是停在旧版本。排查时先查看 /usr/libexec/java_home -V 的输出,确认注册列表里谁排在前面,然后通过设置 JAVA_HOME 到目标版本路径,或者在 IDE 项目结构里显式指定,就能解决。
5. Linux 平台下载安装与环境配置全流程
5.1 apt 和 dnf 包管理器安装:一条命令解决大部分场景
Linux 安装 JDK21 最直接的路径是用发行版的包管理器。Ubuntu、Debian 系统使用 apt,Fedora、RHEL、CentOS 使用 dnf 或 yum。Ubuntu 24.04 及更新的系统,直接执行:
sudo apt update sudo apt install openjdk-21-jdk
这个命令会同时安装运行时和 javac 编译器,是开发环境需要的完整 JDK。如果只是运行 Java 程序,可以只装 openjdk-21-jre-headless,但作为开发者还是建议装 jdk,以 免后续编译和调试时缺这少那。Fedora 和 RHEL 系的对应命令:
sudo dnf install java-21-openjdk-devel
注意 Fedora 系的包名带了 -devel 后缀才是完整 JDK,不带是 JRE。CentOS 7 和部分老系统源里可能没有 java-21-openjdk 这个包,这种情况建议直接跳到 5.2 节用 tar.gz 手动安装。
用包管理器装的 JDK21 会被安装到 /usr/lib/jvm/ 目录下,系统会自动注册 update-alternatives 里的 java 和 javac 命令。安装完成后执行 java -version 验证即可。需要说明的是,不同发行版软件源里的 OpenJDK 版本和补丁水平有一定滞后,而且软件源默认的更新方式和官方稍有区别,想追最新的安全问题补丁需要关注发行版发布渠道。
5.2 tar.gz 手动安装:服务器和特殊场景的无脑选择
Linux 服务器上装 JDK,我更推荐 tar.gz 手动安装,原因是可控性最强。包管理器装到 /usr/lib/jvm 的路径对某些工具脚本来说路径不直观,而手动解压到 /opt 目录后,JAVA_HOME 可以精准指向,卸载和切换版本也非常清楚。
先从 Adoptium 官网或者 Oracle 官网下载对应架构的压缩包,假设下载到 /tmp 目录,执行:
sudo mkdir -p /opt/java sudo tar -zxvf /tmp/OpenJDK21U-jdk_x64_linux_hotspot_21.0.1_12.tar.gz -C /opt/java
解压后确认目录名,例如 /opt/java/jdk-21.0.1+12。接着给系统配置环境变量,Ubuntu、Debian 推荐在 /etc/profile.d/ 下新建一个脚本,这样所有用户登录时都会自动加载:
sudo vi /etc/profile.d/jdk21.sh
文件内容:
export JAVA_HOME=/opt/java/jdk-21.0.1+12 export PATH=$JAVA_HOME/bin:$PATH
保存后执行 source /etc/profile 或重新登录终端,然后验证。如果你只想给当前用户配置,就把同样的内容写入 ~/.bashrc、~/.zshrc 或 ~/.profile,哪个 shell 就写哪个文件,配置文件文件名一定要准确。手动安装还有一个额外好处:可以灵活创建软链接,比如把 JAVA_HOME 指向 /opt/jdk-current,升级时只改软链接,不动项目配置。
5.3 update-alternatives 多版本管理:Linux 系统的版本切换利器
Linux 系统如果安装了多个 JDK,比如 JDK8 和 JDK21 并存,可以用 update-alternatives 这个系统工具来管理 java 和 javac 命令的默认指向。包管理器安装的 OpenJDK 一般会自动注册,手动解压的则需要自己添加。
先查看当前的 java 版本和候选列表:
update-alternatives --config java update-alternatives --config javac
执行第一条命令,系统会列出所有已注册的 java 版本,你输入对应数字回车即可切换默认 java;第二条类似,javac 需要单独切换。需要在候选列表里手动添加版本时可以执行:
sudo update-alternatives --install /usr/bin/java java /opt/java/jdk-21/bin/java 2100 sudo update-alternatives --install /usr/bin/javac javac /opt/java/jdk-21/bin/javac 2100
优先级数字越大越靠前,之后就可以用 update-alternatives --config 交互式切换。但注意 JAVA_HOME 环境变量和 update-alternatives 是两条线:命令行 java 走的哪个版本由 update-alternatives 决定,而 Maven、Gradle、Tomcat 这类工具读的是 JAVA_HOME。所以 Linux 上多版本管理最稳妥的做法是同时维护两套:JAVA_HOME 指向当前项目需要的版本,update-alternatives 让系统 java 命令也跟上,避免手滑。
6. 多版本 JDK 共存与切换:一台机器跑多个项目的刚需
6.1 为什么会有多版本需求,实际场景中容易出现什么问题
Java 生态里多版本并存几乎是所有团队都要面对的现实:老项目停在 JDK8,新服务起步就是 JDK17 或 JDK21,你在一台开发机上要编译老的维护分支,又要跑新项目的微服务,换版本太频繁让人抓狂。更麻烦的是,不同版本之间除了语法差异,还有依赖库的兼容性问题,某些老框架在 JDK17 上直接启动报错,只能老老实实切回 JDK8。
多版本切换最容易出问题的有两处。第一处是环境变量只配了一个,项目之间来回切要手动改 JAVA_HOME,改完忘记刷新终端就编译,报错报得莫名其妙。第二处是 IDE 和命令行不同步,命令行里 java -version 是 JDK21,但 Maven 编译用的是 IDEA 里配置的 JDK8,构建结果自然和预期不一致。
所以多版本管理的核心不是“装多少个版本”,而是“让每个项目能准确指定它要的版本”。这里的理想状态是:环境变量提供全局默认,项目级配置覆盖默认值。每个构建工具都有覆盖机制,下面会讲到。
6.2 三平台多版本切换实操:从改环境变量到 sdkman
在 Windows 上,最简单的方式是用批处理脚本切换 JAVA_HOME。新建两个脚本,比如 jdk21.bat:
@echo off setx JAVA_HOME "C:\Java\jdk-21" >nul setx Path "%Path%;%JAVA_HOME%\bin" >nul echo JDK21 set as default.
注意 setx 修改环境变量后不会影响当前已经打开的终端,需要新开 CMD 验证。更安全的做法是不改全局 Path,只把 %JAVA_HOME%\bin 作为唯一入口,因为多个版本的 bin 都往 Path 里塞,迟早顺序错乱。所以建议:Path 里永远只留 %JAVA_HOME%\bin,切换版本时只改 JAVA_HOME,不要往 Path 再追加其他 JDK 路径。
不过 Windows 原生环境对多版本切换的支持一直很弱,脚本改来改去容易引入问题。如果你的环境里装了 WSL,或者用 Git Bash,强烈建议直接使用 sdkman 来管理,它在 Linux/macOS 体验很好,Windows 下配合 Git Bash 也能用。安装 sdkman 的命令:
curl -s "https://get.sdkman.io" | bash
装完执行 source "$HOME/.sdkman/bin/sdkman-init.sh",然后就可以用 sdk list java 查看可安装版本,sdk install java 21.0.1-tem 安装指定版本,sdk default java 21.0.1-tem 设置默认版本。核心优势在于一个命令完成安装、切换、卸载,JDK 路径完全托管,不用手工维护环境变量。
macOS 原生自带 /usr/libexec/java_home 这个命令,配合 sdkman 或者直接修改 JAVA_HOME 都是不错的选择。我的日常做法是 sdkman 管理版本,但 IDE 里每个项目再单独指定 SDK 路径,两条线互不干扰。Linux 服务器则用 update-alternatives 管理系统命令,用 JAVA_HOME 管理工具链指向,这个在前一章已经说过。
6.3 在 IDE 和构建工具里精确指定 JDK21
多版本切换的最后一道关卡是构建工具和 IDE。IntelliJ IDEA 中,打开 File -> Project Structure -> Project,在 Project SDK 下拉框里选择 JDK21,如果下拉框里没有,点 Add JDK 手动添加安装路径;在 Settings 里还可以设置 Gradle 的 Gradle JVM 和 Maven 的 Java SDK,让构建用的 JDK 和项目语言级别一致。
VSCode 用户需要先安装 Extension Pack for Java,然后打开设置,搜索 java.jdt.ls.java.home,设置成 JDK21 的路径,同时把 java.configuration.runtimes 配置成多个版本供选择。Maven 项目可以在 ~/.m2/settings.xml 的 profiles 里配置 jdk 版本,也可以在 pom.xml 里指定 maven.compiler.source 和 maven.compiler.target 为 21,Gradle 项目则在 build.gradle 里设置 java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }。
还有一个容易被忽略的点:用 Maven 或 Gradle 构建时,命令行工具选择 JDK 是按照 JAVA_HOME 环境变量来的,而 IDE 内置构建可能忽略环境变量使用 IDE 自己的配置。所以当你在终端 mvn clean package 和 IDEA 里 Build 得到的结果不一样时,先检查两边各自用的 JDK 是不是同一个,这个问题排查起来最能节省时间。
7. 常见问题与排查技巧实录
7.1 高频问题速查表
我在三个平台里教过不少同事配置 JDK,也处理过各种环境问题,下面这张表基本覆盖了绝大多数高频坑,可以直接当速查手册使用。
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| java 不是内部或外部命令(Windows) | JAVA_HOME 未设置或 PATH 未包含 %JAVA_HOME%\bin | 检查环境变量,确认安装目录存在 |
| java -version 显示旧版本 | PATH 里旧 JDK 路径排在前面 | 把 %JAVA_HOME%\bin 移到最前,删除旧路径 |
| javac 可用但 java 不可用 | 只配了 JRE 路径或 PATH 里有 java 的旧入口 | 确认 JAVA_HOME 指向 JDK 根目录而非 JRE |
| Windows 新开 CMD 仍不生效 | 系统变量和用户变量冲突 | 建议统一在用户变量配置,重新登录系统 |
| macOS 终端找不到 java | Homebrew keg-only,未配 PATH | 在 ~/.zshrc 加 export PATH=$JAVA_HOME/bin:$PATH |
| macOS GUI 工具不识别 JDK21 | 图形应用不读 shell 配置 | 用 sudo ln -sfn 注册到 /Library/Java/JavaVirtualMachines |
| Linux javac 命令不存在 | 只装了 JRE | 安装 openjdk-21-jdk 或 java-21-openjdk-devel |
| Linux 下 JAVA_HOME 没生效 | profile 文件没有 source | 检查 /etc/profile.d 脚本或用户 shell 配置 |
| mvn 编译用错 JDK 版本 | Maven 读取的是 JAVA_HOME | 调整 JAVA_HOME 指向目标 JDK,确认 mvn -version |
7.2 几个让我折腾最久的坑,写成心得给你避雷
第一个坑是 Windows 的 System32 目录里有个 java.exe。某些 Oracle 安装器会把 java.exe 复制到 C:\Windows\System32 下,而这个目录在 PATH 中的优先级极高,导致你无论怎么改 JAVA_HOME,java -version 都是旧版。排查方法是执行 where java,如果第一行输出是 C:\Windows\System32\java.exe,那问题就在这里,找到并移除该文件,或者用管理员权限重新排序 PATH。
第二个坑是使用 setx 命令修改 PATH 时把整个 PATH 截断了。setx 有一个限制,变量总长度超过 1024 字符时会把内容截断,而 Windows 的 PATH 往往很长,用 setx 改一次就可能导致一堆命令失效。更安全的做法是在环境变量面板里手动编辑,或者用 PowerShell 的 [Environment]::SetEnvironmentVariable 方法来精确修改机器级变量,这个函数不会被截断。
第三个坑是 macOS 上 java_home 命令返回空。如果你明明已经用 dmg 安装了 JDK21,执行 /usr/libexec/java_home -v 21 却什么也不返回,多半是 JDK 没被注册到系统目录。检查一下 /Library/Java/JavaVirtualMachines 下有没有 jdk-21.jdk,如果没有,可以直接用软链接把它指过来,一条命令就能解决。
第四个坑是 Linux 上环境变量写错文件。很多教程统一让你写 /etc/profile,但如果你的桌面环境用的不是登录 shell 链,启动 IDE 时未必会读这个文件。我建议把 JAVA_HOME 写入 /etc/profile.d/jdk21.sh 这种全局脚本,同时把 export 语句追加到自己的 ~/.zshrc 或 ~/.bashrc,双保险能覆盖绝大多数场景。
7.3 下载慢和安装包损坏的应对思路
JDK21 安装包体积并不小,在部分网络环境下,从 Oracle 官网或 GitHub Releases 下载可能很慢,甚至时不时中断。执行前先看官方提供的 SHA-256 校验值,下载完用本地命令比对,避免解压时才发现压缩包损坏,白等半天。
首选的加速方案是更换下载源。Adoptium 提供多个镜像仓库,国内访问 Adoptium 的 GitHub Release 慢的话,可以走清华 TUNA 镜像或者华为云的开源镜像站,它们会定期同步。Oracle JDK 没有官方镜像,但很多公司和教育机构内部会维护自己的软件分发服务,内网环境下优先问运维要内部源,速度基本是秒开。
如果你是 Linux 用户,还可以直接配 apt 源来装 Temurin,Adoptium 官方提供了仓库配置,写入 /etc/apt/sources.list.d/ 之后 apt update && apt install temurin-21-jdk 就能从镜像自动同步,速度比手动下载稳定太多。macOS 用户就直接依赖 Homebrew 源,brew 的下载失败重试机制比浏览器下载更健壮。
我个人在实际操作中养成的习惯是先跑包管理器方案,实在没有才手动下载。一次配置好源和包管理工具后,以后安装任何版本的 JDK 都是一条命令的事,这套先花时间把基础工具理顺的做法,后续体验会舒服很多。最后再分享一个小技巧:安装完 JDK21 后顺手在终端跑一条 java --list-env 或者直接用 jshell 执行两行代码试试模块系统,能快速确认安装环境是否可用,比反复看版本号直观得多。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
