JDK 21 是继 JDK 17 之后的又一个 LTS 长期支持版本,从 2023 年 9 月正式发布到现在,已经成了不少团队生产环境里的默认选择。我最近帮几个朋友处理过 JDK 21 的安装问题,发现大家卡住的地方其实高度集中:要么是下载源选错导致装了个来路不明的包,要么是环境变量配完java -version还是报"不是内部或外部命令",要么是 Mac 上装完不知道 JAVA_HOME 到底该指向哪一层目录。这篇就把 Windows、macOS、Linux 三个平台从下载到环境变量配置的完整流程拆开讲清楚,顺带把那些文档里不会写的坑一并交代了。不管你是刚接触 Java 的新手,还是想从 JDK 8 升级到 21 的老手,照着走一遍基本都能一次配通。
1. 装之前先想清楚:为什么是 JDK 21,以及该选哪个发行版
1.1 JDK 21 到底带来了什么,值不值得升
很多人装 JDK 21 是因为教程里说"新版本好",但具体好在哪说不清楚。我简单说几个实际开发中能直接感受到的点。JDK 21 引入了虚拟线程(Virtual Threads)的正式版本,这是 Project Loom 的成果,简单理解就是以前一个请求占一个操作系统线程,线程池开个几百就顶天了,现在可以用虚拟线程轻松撑起几十万的并发任务,写起来还是同步代码的写法,不用改成响应式那一套。另外还有分代 ZGC、记录模式(Record Patterns)、switch 的模式匹配等特性,这些在写业务代码时能明显减少样板代码。
从支持周期看,JDK 21 是 LTS 版本,官方支持到 2031 年左右,这意味着你现在升级上去,未来七八年不用再折腾大版本迁移。相比之下 JDK 17 虽然也是 LTS,但虚拟线程这类关键特性没有,如果你的项目涉及高并发 IO 场景,21 的收益是很直接的。所以我的建议是:新项目直接上 21,老项目如果依赖库都兼容,也值得规划升级。
1.2 Oracle JDK、OpenJDK、各种发行版到底选哪个
这是新手最容易懵的地方。市面上的 JDK 21 有好几个来源,我列个表对比一下,你按自己的场景选就行。
| 发行版 | 提供方 | 授权 | 适用场景 | 我的建议 |
|---|---|---|---|---|
| Oracle JDK | Oracle | NFTC 免费商用 | 通用开发 | 可用,但注意授权条款 |
| Oracle OpenJDK | Oracle | GPLv2+CPE | 通用开发 | 纯净,适合学习 |
| Eclipse Temurin | Adoptium | GPLv2+CPE | 生产环境 | 我个人最推荐 |
| Amazon Corretto | Amazon | GPLv2+CPE | 生产环境、云上 | AWS 用户首选 |
| Azul Zulu | Azul | GPLv2+CPE | 生产环境 | 支持周期长 |
| Microsoft Build of OpenJDK | 微软 | GPLv2+CPE | Azure、Windows | Windows 用户友好 |
我自己的习惯是:本地开发用 Eclipse Temurin,因为它的安装包做得规范,Windows 有 msi、macOS 有 pkg、Linux 有 deb/rpm,环境变量基本自动配好,省心。生产环境如果跑在云上,就跟着云厂商推荐的发行版走,比如 AWS 上就用 Corretto。这里要提醒一句,别去那些乱七八糟的下载站下 JDK,很多捆绑了广告软件甚至改了包内容,一定要从官方或 Adoptium 这类可信源下载。
提示:判断一个 JDK 发行版是否靠谱,看它是否公开源码、是否有明确的授权协议、是否有长期维护承诺。三者缺一,谨慎使用。
1.3 版本号里的门道:21.0.1、21.0.2 该选哪个
JDK 的版本号格式是主版本.次版本.安全版本,比如 21.0.5。主版本 21 代表这是 JDK 21,后面的 0.5 是补丁更新。原则很简单:永远选当前最新的补丁版本。因为补丁版本只修 bug 和安全漏洞,不引入新特性,兼容性有保证。比如现在最新是 21.0.5,那就下 21.0.5,别去下 21.0.0 那个初始版。安全补丁对生产环境尤其重要,很多漏洞就是靠这些补丁修的。
2. Windows 平台:从下载到环境变量一次配通
2.1 下载安装包的正确姿势
Windows 上我推荐直接下 msi 安装包,而不是 zip 压缩包。原因很简单:msi 会自动帮你配好 PATH 和 JAVA_HOME,zip 包解压完还得手动配,新手很容易在这里翻车。去 Adoptium 官网(adoptium.net),找到 JDK 21 的下载区,选 Windows x64 的 msi 包。如果你的机器是 ARM 架构(比如某些 Surface),就选 aarch64 版本。
下载前确认一下系统架构:右键"此电脑"→"属性",看"系统类型"那一栏。绝大多数人是 x64,少数新设备是 ARM64。下错了架构,装完运行会直接报错或者性能异常。文件大小大概 180MB 左右,如果下下来只有几十 KB,那多半是下到了网页而不是安装包,重新点一次。
2.2 安装过程中的关键选项
双击 msi 后,安装向导里有两个地方要注意。第一个是安装路径,默认会装到C:\Program Files\Eclipse Adoptium\jdk-21.0.5.9-hotspot\这样的目录。我建议不要改路径,就用默认的,因为路径里带空格和特殊字符时,某些老工具会解析出错。如果你非要改,也请确保路径里没有中文和空格。
第二个关键选项是安装向导里会问你要不要配置 JAVA_HOME 和 PATH,还有要不要设置 JavaSoft 注册表项。这几个全部勾上。勾上之后,安装程序会自动帮你把环境变量配好,省掉后面手动配置的一大半工作。很多人装完发现环境变量没配,就是因为这一步没勾。
2.3 手动配置环境变量的完整步骤
即使 msi 自动配了,我也建议你手动检查一遍,因为有时候自动配置会漏。步骤如下:
- 按
Win + R,输入sysdm.cpl,回车,打开"系统属性"。 - 点"高级"选项卡,再点"环境变量"。
- 在"系统变量"区域,点"新建",变量名填
JAVA_HOME,变量值填你的 JDK 安装目录,比如C:\Program Files\Eclipse Adoptium\jdk-21.0.5.9-hotspot。注意这里不要带\bin,JAVA_HOME 指向的是 JDK 根目录。 - 找到"系统变量"里的
Path,双击编辑,点"新建",添加%JAVA_HOME%\bin。把它移到列表靠前的位置,避免被其他 Java 版本的路径抢先。 - 一路点确定保存。
这里有个高频错误:有人把JAVA_HOME配成了C:\Program Files\Eclipse Adoptium\jdk-21.0.5.9-hotspot\bin,多了个\bin。这样配完,java命令能用,但 Maven、Gradle 这些工具会找不到 JDK,因为它们读 JAVA_HOME 后会自己拼\bin,结果变成\bin\bin。记住:JAVA_HOME 到根目录,PATH 里才加 \bin。
2.4 验证配置是否生效
配完别急着关窗口,先验证。关键点:一定要重新开一个命令行窗口,因为环境变量是启动时读取的,老窗口读的还是旧值。新开一个 cmd 或 PowerShell,依次执行:
java -version javac -version echo %JAVA_HOME%正常输出应该是类似openjdk version "21.0.5" 2024-10-15这样的信息,javac版本也要一致,echo %JAVA_HOME%要输出你配的路径。如果java -version报"不是内部或外部命令",说明 PATH 没配好;如果版本号是 1.8 或 17,说明系统里有多个 Java,PATH 顺序不对,把 JDK 21 的路径往前挪。
注意:Windows 上如果同时装了多个 JDK,PATH 里谁在前谁生效。建议只保留一个 JDK 的 bin 在 PATH 里,其他的删掉,避免混乱。
3. macOS 平台:pkg 安装与 JAVA_HOME 的坑
3.1 用 pkg 还是用包管理器
macOS 上装 JDK 21 有两条路:下 pkg 安装包,或者用 Homebrew。我两种都用过,说下区别。pkg 安装包的好处是图形化、一步到位,装完系统会自动在/Library/Java/JavaVirtualMachines/下建好目录,/usr/libexec/java_home也能识别到。Homebrew 的好处是升级方便,brew upgrade一条命令搞定,而且卸载干净。
如果你只是本地开发,我推荐 Homebrew,命令是:
brew install --cask temurin@21如果你不想装 Homebrew,或者公司环境限制,那就去 Adoptium 下 pkg 包,双击安装,一路下一步即可。两种方式装完,JDK 都会出现在标准位置。
3.2 macOS 上 JAVA_HOME 到底该指向哪
这是 Mac 用户问得最多的问题。macOS 有个特殊工具叫java_home,路径是/usr/libexec/java_home,它能帮你找到当前系统里的 JDK。你可以这样用:
/usr/libexec/java_home -v 21它会输出 JDK 21 的实际路径,比如/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home。注意这个路径以 Contents/Home 结尾,这才是 macOS 上 JDK 的"根目录",JAVA_HOME 要指向这里,而不是.jdk那一层。
配置环境变量时,macOS 现在默认是 zsh,所以编辑~/.zshrc(老版本是 bash 就编辑~/.bash_profile):
export JAVA_HOME=$(/usr/libexec/java_home -v 21) export PATH=$JAVA_HOME/bin:$PATH这样写的好处是,以后你升级到 21.0.6,路径变了也不用改配置,java_home会自动找到最新的 21。如果你写死路径,每次升级都得手动改,很麻烦。
3.3 让配置立即生效并验证
改完~/.zshrc后,执行:
source ~/.zshrc java -version echo $JAVA_HOME如果java -version还是老版本,检查一下是不是有其他 JDK 的路径在 PATH 里更靠前,或者~/.zshrc里有没有重复的 export。macOS 上还有个坑:系统自带的/usr/bin/java是个 stub,它会弹窗提示你装 Java,如果你 PATH 里/usr/bin在前,就会先命中这个 stub。解决办法就是把$JAVA_HOME/bin放到 PATH 最前面,我上面的写法已经这么做了。
4. Linux 平台:apt、yum 与手动解压三种方式
4.1 Ubuntu/Debian 用 apt 安装
Ubuntu 上最省事的方式是用 apt,但要注意默认源里的版本可能不是最新的 21。先更新索引:
sudo apt update sudo apt install -y temurin-21-jdk如果提示找不到包,需要先加 Adoptium 的源。加源步骤稍微繁琐,我一般直接用下面的方式:下载 deb 包手动装。去 Adoptium 下temurin-21-jdk_21.0.5_amd64.deb,然后:
sudo dpkg -i temurin-21-jdk_21.0.5_amd64.deb装完 JDK 会在/usr/lib/jvm/下,比如/usr/lib/jvm/temurin-21-jdk-amd64。
4.2 CentOS/RHEL 用 yum 或 rpm
CentOS 系用 rpm 包:
sudo rpm -ivh temurin-21-jdk-21.0.5.x86_64.rpm或者用 yum 本地安装:
sudo yum localinstall -y temurin-21-jdk-21.0.5.x86_64.rpm装完同样在/usr/lib/jvm/下。这里提醒一句,有些老系统自带的 yum 源里 JDK 版本很旧,别用yum install java-21-openjdk这种,除非你确认源里有 21。
4.3 手动解压 tar.gz 的通用做法
如果你没有 root 权限,或者想装到自定义目录,就用 tar.gz 包。这种方式最灵活,也最通用,任何 Linux 发行版都能用:
# 下载后解压到 /opt sudo tar -zxvf OpenJDK21U-jdk_x64_linux_hotspot_21.0.5_11.tar.gz -C /opt # 重命名方便管理 sudo mv /opt/jdk-21.0.5+11 /opt/jdk-21然后配置环境变量。Linux 上我推荐写到/etc/profile.d/jdk21.sh,这样对所有用户生效:
sudo tee /etc/profile.d/jdk21.sh <<'EOF' export JAVA_HOME=/opt/jdk-21 export PATH=$JAVA_HOME/bin:$PATH EOF写完执行source /etc/profile.d/jdk21.sh生效。如果只想对当前用户生效,就写到~/.bashrc里。
4.4 Linux 环境变量配置失败的常见原因
Linux 上配环境变量失败,八成是这几个原因。第一,source的文件不对,比如你写到了/etc/profile但用的是 zsh,zsh 不读这个文件,得写到/etc/zsh/zprofile或~/.zshrc。第二,PATH 拼接时把$PATH写成了$PATH:后面没内容,或者漏了$PATH导致系统命令全找不到。第三,用sudo执行java时,sudo 默认不继承用户环境变量,得用sudo -E或者配sudoers里的env_keep。
排查方法很简单,执行echo $JAVA_HOME和echo $PATH看输出对不对,再用which java看命中的是哪个 java。如果which java指向/usr/bin/java而不是你的 JDK,说明 PATH 顺序有问题。
5. 多版本共存与切换:一台机器装多个 JDK 怎么办
5.1 为什么需要多版本共存
实际开发中经常遇到这种情况:老项目还在 JDK 8 上跑,新项目要用 21,你不可能为了切项目就重装 JDK。所以多版本共存是刚需。核心思路是:每个 JDK 装到独立目录,环境变量通过切换 JAVA_HOME 来指向不同的版本。
5.2 Windows 上的切换方案
Windows 上我推荐用一个小脚本切换。建两个 bat 文件,比如use-jdk8.bat和use-jdk21.bat,内容分别是:
@echo off setx JAVA_HOME "C:\Program Files\Java\jdk1.8.0_381" setx PATH "%JAVA_HOME%\bin;%PATH%" echo Switched to JDK 8注意setx是永久设置,改完要新开窗口才生效。更优雅的做法是用符号链接:把C:\Java\current指向当前用的 JDK,JAVA_HOME 永远指向C:\Java\current,切换时只改链接指向。这样环境变量不用动,切换更干净。
5.3 macOS 和 Linux 上的切换方案
macOS 上因为有了java_home工具,切换特别方便。你可以在~/.zshrc里定义别名:
alias jdk8='export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)' alias jdk21='export JAVA_HOME=$(/usr/libexec/java_home -v 21)'需要哪个版本就执行哪个别名。Linux 上可以用update-alternatives管理:
sudo update-alternatives --install /usr/bin/java java /opt/jdk-21/bin/java 2100 sudo update-alternatives --install /usr/bin/java java /opt/jdk-8/bin/java 800 sudo update-alternatives --config java最后一条命令会列出所有版本让你选,选完java命令就指向对应版本。不过update-alternatives只管java命令,JAVA_HOME 还得手动改,所以更推荐用脚本切换 JAVA_HOME。
6. 装完之后的验证与常见问题排查
6.1 一套完整的验证清单
装完 JDK 21 后,别只看java -version就完事,我建议跑一遍下面这套检查:
| 检查项 | 命令 | 预期结果 |
|---|---|---|
| Java 运行时版本 | java -version | 显示 21.x |
| 编译器版本 | javac -version | 显示 21.x |
| JAVA_HOME 变量 | echo $JAVA_HOME(Win 用%JAVA_HOME%) | 指向 JDK 根目录 |
| java 命令来源 | which java(Win 用where java) | 指向 JDK 的 bin |
| 编译运行测试 | 写个 Hello.java 编译运行 | 正常输出 |
最后那个编译运行测试最实在,能一次性验证 java 和 javac 都配对了。写个最简单的:
public class Hello { public static void main(String[] args) { System.out.println("JDK " + System.getProperty("java.version")); } }javac Hello.java编译,java Hello运行,输出JDK 21.0.5就说明全通了。
6.2 高频问题速查表
我把这些年遇到的和网上问得最多的问题整理成表,方便你对号入座。
| 问题现象 | 根本原因 | 解决办法 |
|---|---|---|
java不是内部或外部命令 | PATH 没配或没生效 | 检查 PATH 含%JAVA_HOME%\bin,重开窗口 |
java -version显示旧版本 | 多个 JDK,PATH 顺序错 | 把目标 JDK 的 bin 移到 PATH 最前 |
| Maven 报找不到 JDK | JAVA_HOME 配到了 bin 目录 | JAVA_HOME 改为 JDK 根目录 |
javac能用但java不行 | 只配了部分路径 | 确认 bin 目录完整加入 PATH |
Mac 上java弹窗提示安装 | 命中了系统 stub | 把$JAVA_HOME/bin放 PATH 最前 |
| Linux sudo 下找不到 java | sudo 不继承环境变量 | 用sudo -E或配 sudoers |
| 环境变量改了不生效 | 没 source 或没重开窗口 | source 配置文件或新开终端 |
| 编译报"不支持发行版本 21" | IDE 或构建工具没设对 | 检查 IDE 的 SDK 和编译级别设置 |
6.3 几个容易被忽略的细节
第一个细节是 IDE 的配置。你系统环境变量配好了,但 IntelliJ IDEA 或 Eclipse 里可能还指向老 JDK。IDEA 里要去File → Project Structure → SDK里把项目 SDK 改成 21,同时Project language level也要设成 21。Eclipse 里在Preferences → Java → Installed JREs里添加 JDK 21。
第二个细节是构建工具的配置。Maven 的pom.xml里要设<maven.compiler.source>21</maven.compiler.source>和<maven.compiler.target>21</maven.compiler.target>,或者用<release>21</release>。Gradle 里要设sourceCompatibility = JavaVersion.VERSION_21。这些不设,编译时还是会按老版本处理,可能报错。
第三个细节是某些第三方库的兼容性。比如你搜热词里提到的 aspose-words,这类库对 JDK 版本有要求,升级 JDK 21 前要确认你用的版本支持 21,否则运行时会报UnsupportedClassVersionError。一般库的官方文档或 release notes 里会写明支持的 JDK 范围,升级前查一下能省很多事。
提示:升级 JDK 大版本前,先在测试环境跑一遍完整的构建和测试,确认所有依赖库都兼容,再动生产环境。
7. 我踩过的坑和几条实在建议
说几个我自己真实踩过的坑。有一次在 Windows 上配完环境变量,java -version死活显示 1.8,查了半天发现是之前装 Oracle 时在 PATH 里留了个C:\ProgramData\Oracle\Java\javapath,这个路径排在前面,里面是 Oracle 的 java.exe 快捷方式。解决办法就是把这个路径从 PATH 里删掉,或者把 JDK 21 的路径挪到它前面。这种"隐藏"的 Java 路径特别坑,因为你在环境变量界面里不一定一眼看到。
还有一次在 Linux 服务器上,用sudo跑脚本时 java 找不到,排查发现是 sudo 默认重置了环境变量。后来在/etc/sudoers里加了Defaults env_keep += "JAVA_HOME PATH"才解决。如果你经常用 sudo 跑 Java 相关命令,这个配置值得加上。
最后给几条实在建议。第一,下载 JDK 只从官方或 Adoptium、Corretto 这类可信源,别图快用第三方下载站。第二,环境变量配完一定要新开窗口验证,别在老窗口里反复试。第三,多版本共存时用脚本或符号链接切换,别每次手动改环境变量,容易改乱。第四,升级大版本前先查依赖库兼容性,尤其是那些用了字节码增强或反射的库。第五,把 JDK 的安装路径和版本记在笔记里,过几个月你自己都忘了装在哪、装的哪个小版本。
这套流程我在 Windows 11、macOS Sonoma、Ubuntu 22.04 上都实测过,按上面的步骤走,基本不会出问题。真遇到卡住的地方,先看echo $JAVA_HOME和which java这两个输出,八成问题都能定位到。