news 2026/10/29 17:18:20

在macOS上用tar.gz安装JDK 17并实现多版本切换

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在macOS上用tar.gz安装JDK 17并实现多版本切换

简介:面向macOS x64架构开发者的Java 17长期支持版完整JDK二进制包,解决在苹果Intel芯片Mac上搭建稳定Java开发与运行环境的问题,适合本地开发、生产部署、离线安装及构建镜像等场景。依据Oracle免费条款,JDK 17二进制文件可在生产中免费使用并可免费再分发。压缩包共392个文件,大小约169.24MB,文件类型覆盖jmod模块文件、license与copyright授权说明、dylib动态链接库、properties配置和policy安全策略;同时包含javac、jshell、jcmd、jpackage等常用开发诊断工具,以及源码模块和说明文档,结构清晰,便于按需查阅。目前已有296人学习下载。解压后即可调用核心命令,无需额外联网;也可结合模块文件、源码与文档,深入理解JDK的模块化组织方式和内置工具链。对于需要统一布置团队开发环境、制作离线工具包或搭建CI/CD基础镜像的运维与架构人员,这份资源同样适用。

1. 从 jdk-17_macos-x64_bin.tar.gz 说起:一份能直接解压的 Java 17 LTS

“jdk-17_macos-x64_bin.tar.gz”这个文件名,熟手一眼就能看出门道:Oracle 官方发布的 JDK 17(Java 17 LTS)macOS x64 平台压缩包版。我身边好几个同事第一次看到它都愣一下——JDK 不是都双击 dmg 安装吗?但真正在 macOS 上手工管理过多个 JDK 版本的人,反而更愿意要这份 tar.gz:不需要安装器弹窗,不会在系统目录里留一堆卸载不干净的残留,解压之后改一下环境变量就能用。

它解决的是三类问题:给开发机快速装一套干净的 Java 17 LTS;在已经装了 JDK 8 或 JDK 21 的机器上降级、切换到 17;给 DBeaver、Jmeter 这类需要指定 JDK 的工具提供一个不污染系统的可用运行环境。适合已经过了“点下一步装 Java”阶段、愿意自己掌控目录和版本的人。接下来我按实际动手顺序,把解压、配环境变量、多版本切换和踩坑记录完整过一遍。

2. 为什么这份 tar.gz 值得保留:安装方式选型与目录规划

2.1 tar.gz、dmg、Homebrew 三种装法的差别

在 macOS 上装 JDK,主流路径无非三种:Oracle 官方 dmg 安装器、Homebrew 的 openjdk@17、以及这份 tar.gz 解压版。它们的本质差别不在版本号,而在“安装之后你还能不能控制它”。

dmg 安装器会把 JDK 写进 /Library/Java/JavaVirtualMachines/ 并注册系统 Java 目录,好处是全局可用、IDEA 能自动识别,坏处是版本切换时你会陷入“系统里同时存在好几份 JDK、但 java -version 不知道听谁的”的尴尬。我见过不止一次 dmg 装完 17 后执行 java -version 显示的还是 8——PATH 被某个老配置抢先了,卸载脚本还未必删得干净。

Homebrew 的 openjdk@17 是另一种常见选择,装完还要手动 sudo ln -sfn 把目录链接进系统 Java 目录,否则 IDEA 同样找不到。而且 Homebrew 管理的是 OpenJDK 构建版,与 Oracle 官方构建在个别参数默认值上有细微差异;brew upgrade 的时候版本还可能被顺带升掉,你必须花精力 pin 住版本。

tar.gz 解压版的价值在于:JDK 就是一个普通目录,目录里就是完整 SDK。没有任何系统目录写入、没有注册动作。它放在哪、叫什么名字,完全由你决定。这正是后续多版本切换和“绿色软件式管理”的基础,也是我把这份资源长期留在硬盘里的原因。

2.2 解压与目录规划:一份可复制的 JDK 根目录

动手前先说我的习惯:先把下载好的 tar.gz 放到稳定位置,通常先留在 ~/Downloads,解压时再落到 /usr/local/java 下,这样后续配 JAVA_HOME 时路径固定,不会因为清理下载目录而失效。

# 确认文件完整,建议校验 SHA-256 shasum -a 256 ~/Downloads/jdk-17_macos-x64_bin.tar.gz # 创建 JDK 目录并解压 sudo mkdir -p /usr/local/java sudo tar -xzf ~/Downloads/jdk-17_macos-x64_bin.tar.gz -C /usr/local/java # 查看解压后的结构 ls /usr/local/java/ # 输出一般是 jdk-17.0.x.jdk/Contents/Home

shasum 这步值得养成习惯:官网页面上会给出对应包的 SHA-256 值,尤其是从镜像站拿包时,先校验再解压能避开损坏包和改名包。tar -xzf 的意思分别对应解压 gzip 压缩、显示解压过程、指定目标目录,-C 后面跟的是落盘位置。解压出来的 jdk-17.0.x.jdk 本质是一个 .jdk bundle,自带 Info.plist,真实 SDK 内容在 jdk-17.0.x.jdk/Contents/Home 这一层,后续所有 JAVA_HOME 配置都要指到这里,指错一层就只能看到空目录。

注意:这份 JDK 对系统是“不可见”的。dmg 装完的 JDK 系统会自动识别,而 tar.gz 解压版在 IntelliJ IDEA 里如果不手动指定路径是搜不到的,所以它天然适合本来就打算手工管理 JDK 的使用方式。

2.3 配置 JAVA_HOME 与 PATH:以 zsh 为例

macOS 从 Catalina 起默认 shell 是 zsh,所以绝大多数情况下你改的是 ~/.zshrc。还在用 bash 的机器就改 ~/.bash_profile,逻辑一样。

# 编辑 zsh 配置,把下面内容加进去 export JAVA_HOME="/usr/local/java/jdk-17.0.x.jdk/Contents/Home" export PATH="$JAVA_HOME/bin:$PATH"

这里为什么不写死 /Library/Java/JavaVirtualMachines?因为那份 JDK 根本不在系统目录里。JAVA_HOME 必须完整指到 Contents/Home 这一层,少了 jdk-17.0.x.jdk 前缀或少了 Contents/Home,java 命令都跑不起来。PATH 里把 $JAVA_HOME/bin 放在最前面,是为了让 shell 优先找到这份 17 而不是系统自带的其它 java。

配置完后执行 source ~/.zshrc,再跑 echo $JAVA_HOME 确认路径已生效。这里有个很容易被忽略的点:如果机器上已经通过 dmg 装过其它 JDK,/usr/libexec/java_home -V 会列出系统识别的所有 JDK,但这份 tar.gz 解压版不在列表里——这是正常的,它没有走系统注册机制,别拿这条来判断安装失败。

# 快速验证 echo $JAVA_HOME # 期望输出 /usr/local/java/jdk-17.0.x.jdk/Contents/Home

到这里,一份干净、可控、路径明确的 JDK 17 就绪了。接下来看它怎么跟机器上可能存在的其它 JDK 和平共处。

3. 多版本共存与降级到 17:同一台 Mac 的版本切换实战

3.1 先想清楚:你要的是“切换”还是“降级”

很多人的真实场景是:电脑里已经装了 JDK 8 或 JDK 21,突然项目要求必须 JDK 17,于是到处搜“jdk降级到17”。这里有个概念要先理清:JDK 8 在老项目里往往仍然有用,你不需要删掉它,你要做的是把当前生效的版本切到 17,也就是“多版本共存 + 切换”,而不是真的把机器降级成一个裸的 JDK 17。

干净的做法是:把 dmg 装的旧 JDK 留在系统目录 /Library/Java/JavaVirtualMachines/,把 JDK 17 的 tar.gz 解压版放到自己的 /usr/local/java/ 下。两者互不干扰:dmg 装的会向系统注册,tar.gz 的不会。哪个生效,取决于 PATH 里谁的 bin 目录先被搜到。这也是 tar.gz 版本在多版本管理上的核心优势——你可以完全不碰系统目录,纯靠用户级配置完成版本控制。

顺带提一句,DBeaver 改 JDK 版本、Jmeter 找不到 JDK 之类的问题,也基本都是这套机制没理清:GUI 工具有自己的 JDK 路径配置,不读 shell 的 PATH,后面避坑章节会展开。

3.2 手动切换:直接改 .zshrc 的朴素方式

最直白的方案是在 .zshrc 里维护两组变量,要用哪个版本就取消哪一组的注释:

# JDK 8(dmg 安装,保留在系统目录) export JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home" export PATH="$JAVA_HOME/bin:$PATH" # JDK 17(tar.gz 解压,自定义目录) # export JAVA_HOME="/usr/local/java/jdk-17.0.x.jdk/Contents/Home" # export PATH="$JAVA_HOME/bin:$PATH"

每次切换版本就是改注释、source 一下。这个方式我在早期用过一段时间,最大的问题是容易翻车:两组变量都忘了注释时,PATH 会以最后写的为准,很容易出现“我以为切到了 17,java -version 却还是 8”的错觉。而且 source ~/.zshrc 只在当前终端窗口有效,新开一个窗口又得重新来。如果你的项目频繁在 8 和 17 之间横跳,下面 jenv 的方式更适合。

3.3 用 jenv 做带状态的版本切换

jenv 是 macOS 上管理多个 JDK 的常用工具。它本身不安装 JDK,只负责把你机器上已有的 JDK 登记起来,按目录或全局来切换版本。

# 安装 jenv(Homebrew 方式) brew install jenv # 把两份 JDK 注册进 jenv jenv add /Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home jenv add /usr/local/java/jdk-17.0.x.jdk/Contents/Home # 设置全局默认版本为 17 jenv global 17.0.13 # 在某个老项目目录里单独指定 8 cd ~/work/legacy-project jenv local 1.8

jenv 的原理是在你的 PATH 前面插入一个 shim,java、javac 这类命令先经过 jenv,由它根据当前目录或全局配置转发到对应 JDK。这意味着你不必反复改注释,到哪个目录就自动用哪个版本。但有一个边界必须知道:jenv 不会自动改写 JAVA_HOME 环境变量,而 Maven 这类构建工具恰恰优先读 JAVA_HOME。所以用 jenv 时要在 .zshrc 里完成 jenv 的初始化配置,官方文档里有固定一段,照抄即可,否则你切版本只切了一半。

3.4 验证降级是否成功:三层确认法

切完版本后别急着开写,先按下面这套流程确认。我实际踩过的坑是:java -version 明明显示 17,mvn -v 里 Java version 却还是 1.8,原因是 Maven 读的是 JAVA_HOME 而不是 PATH 里的 java 指向。

验证层命令看什么
运行时版本java -versionopenjdk version "17.0.x"
编译工具链javac -versionjavac 17.0.x
构建工具读取mvn -v第二行 Java version: 17.0.x

同一台机器上存在多份 JDK 时,这四个命令可能给出四个不同版本,这不算玄学,而是每层工具读取 JDK 的方式不同。只要 java、javac、mvn 三者显示一致,说明这份 JDK 17 真正接管了你的开发链路。

4. 避坑:macOS 上安装和配置 JDK 17 的五个真实翻车现场

4.1 Terminal 提示 Operation not permitted,连 java 都跑不起来

现象:解压 tar.gz 或执行 java -version 时报 Operation not permitted,有时候连 ls /usr/local/java 都没权限。

原因:macOS 的 TCC 权限限制。从“下载”或“桌面”这类目录解压出来的可执行文件,常常带 com.apple.quarantine 扩展属性,Gatekeeper 会拦截执行;另一个常见情况是解压目标目录权限被改乱,系统不允许当前用户写读。

解决:先去掉 quarantine 属性,再检查目录归属。命令参考:

# 去掉隔离属性 xattr -dr com.apple.quarantine /usr/local/java/jdk-17.0.x.jdk # 修正目录归属(当前用户) sudo chown -R $(whoami) /usr/local/java

去掉属性后建议关掉终端重开再验证。如果还不行,去“系统设置-隐私与安全性”里给终端加上“完全磁盘访问权限”。这一步解决了 80% 的“解压了但跑不动”问题。

4.2 source 之后能跑 java,新开终端就 command not found

现象:当前终端里 source ~/.zshrc 后一切正常,关掉终端重新开一个,java 直接找不到了,或者版本跳回旧的。

原因:新终端不会自动加载你改的那份配置文件。你很可能改的是 ~/.bash_profile,但当前 shell 是 zsh;或者 ~/.zshrc 里 PATH 变量被 export PATH="$JAVA_HOME/bin" 直接覆盖,没拼接原有 PATH。

解决:先确认 shell 类型,再纠正配置。执行 echo $SHELL,输出 /bin/zsh 就改 ~/.zshrc;同时检查配置里有没有把 PATH 写丢:

# 正确写法,$PATH 要保留在后面 export PATH="$JAVA_HOME/bin:$PATH"

把这两处改好后,新开终端应该能直接跑到 java -version。

4.3 java -version 显示 17,Maven 和 IDEA 却还是旧版本

现象:命令行验证一切正常,但 mvn -v 显示 Java version 1.8,IDEA 的 Project SDK 里也找不到 17。

原因:Maven 读的是 JAVA_HOME 环境变量,IDEA 默认扫描的是系统 JavaVirtualMachines 注册表,这两个都不依赖当前终端的 PATH。tar.gz 解压的 JDK 没有注册进系统目录,IDEA 自然搜不到;JAVA_HOME 如果没配或指错,Maven 就退回自己找的版本。

解决:Maven 的执行环境先确认 JAVA_HOME 输出:

echo $JAVA_HOME # 必须输出 /usr/local/java/jdk-17.0.x.jdk/Contents/Home

IDEA 里到 Project Structure → Project SDK → Add JDK,手动选择 /usr/local/java/jdk-17.0.x.jdk/Contents/Home 目录。如果是 Gradle 项目,还可以在 build.gradle 里声明 toolchain,让构建工具强制使用 17,这比依赖全局配置更稳。

4.4 镜像站下载的包解压后结构不对或版本对不上

现象:下载的文件名写着 jdk-17_macos-x64_bin.tar.gz,解压后找不到 Contents/Home 目录,或者 javac 命令不存在。

原因:部分第三方镜像站会对官方包二次打包,外壳是 tar.gz、内容却是 zip 结构;也有极少数情况是下载到了 renamed 的 Linux 版,在 macOS 上自然跑不了。

解决:解压后先看第一层目录名,合法结构应该是这样:

jdk-17.0.x.jdk/ └── Contents/ └── Home/ ├── bin/ ├── lib/ └── jmods/

再拿官方 SHA-256 校验值对一遍。这一步虽然麻烦,但能省掉后面排查问题的半天时间。我现在每次从镜像站拿包都强制走 shasum 校验流程,再急也不跳过。

4.5 GUI 工具报找不到 JDK:DBeaver、Jmeter 各自维护自己的路径

现象:DBeaver 首选项里 Java 路径是红的,Jmeter 启动时弹窗提示没有 JRE。

原因:这些 GUI 工具在 Finder 里双击启动时,根本不经过你的 shell 环境变量。它们各自维护一份 JDK 路径配置,DBeaver 在首选项里读,Jmeter 在启动脚本里找 java。

解决:直接手动指定路径。DBeaver 在 Preferences → General → Java 里填 /usr/local/java/jdk-17.0.x.jdk/Contents/Home;Jmeter 在 jmeter 脚本里设置 JVM_HOME,或者直接在系统里保留一份 dmg 安装的 JDK 兜底。说实话这里 tar.gz 方案反而更好给 GUI 工具指路径——路径固定、纯粹,填进去就能认,不像系统目录里有好几个版本还要猜。

5. 验证安装是否可用:用命令行、Maven 和 IDEA 一次性确认

5.1 命令行验证:别只看 java -version

配置完成后我有一套固定验证流程,按顺序执行,每一步看一个层面。

# 看 java 实际来自哪个路径 which java # 期望输出 /usr/local/java/jdk-17.0.x.jdk/Contents/Home/bin/java java -version # 期望输出 openjdk version "17.0.x" 2024-xx-xx LTS javac -version # 期望输出 javac 17.0.x

which java 是最该先看的一条:它直接告诉你命令解析顺序里谁的 bin 排在前面。如果输出 /usr/bin/java,说明你的 PATH 配置没生效,或是系统 Java 目录优先级更高。java -version 确认运行时版本,javac -version 确认编译工具链,两者必须一致。版本不一致的项目,写代码时 IDE 提示正常,一编译就报错,这类问题最难排查。

5.2 用 hello world 验证编译与运行链路

命令看起来是通的,不等于 javac 和 java 真的能配合。我习惯写一个最小 Java 文件走完整编译运行链路:

mkdir -p ~/tmp/jdk17-test && cd ~/tmp/jdk17-test cat > Hello.java <<'EOF' public class Hello { public static void main(String[] args) { System.out.println("JDK17 on macOS OK"); } } EOF javac Hello.java && java Hello # 期望输出 JDK17 on macOS OK

这段的操作逻辑是:javac 把 Hello.java 编译成 Hello.class,java 再启动 JVM 运行它。&& 保证编译成功才执行运行,哪一步失败都会停在原地。如果 javac 编译报错,大概率是 PATH 里 JDK bin 路径没对上;如果 java 运行报错,常见原因是 CLASSPATH 被污染或 JDK 目录被移动过导致 lib 相对路径失效。趁 JDK 刚装好时走一遍这条链路,能确认环境是整体可用的,而不是只活了半条命。

5.3 Maven 项目验证:确认构建工具读的是这份 JDK

建立一个空的 pom.xml,让 compiler 插件按 17 编译:

<project> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>jdk17-check</artifactId> <version>1.0</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> </project>

在项目根目录执行 mvn compiler:compile。如果错误信息里有 invalid target release: 17,说明 Maven 正在运行在一个低于 17 的 JVM 上,编译目标版本超过了运行版本。这时用临时指定 JAVA_HOME 的方式排查:

JAVA_HOME=/usr/local/java/jdk-17.0.x.jdk/Contents/Home mvn -v | grep "Java version"

注意这里 JVM_HOME 只对这一次命令生效,不会污染终端配置。如果输出 Java version: 17.0.x,说明 Maven 本身能识别这份 JDK,问题大概率出在 maven-compiler-plugin 版本太旧。升级到 3.11.0 以上再跑一次即可。

5.4 IDEA 里指定 JDK 17:Project SDK 与 Gradle toolchain

IDEA 打开已有项目后,到 File → Project Structure → Project SDK 点 Add JDK,选目录时指向 /usr/local/java/jdk-17.0.x.jdk/Contents/Home,IDEA 会自动识别出版本号 17。然后看 SDK 旁边的 Language level 下拉菜单里有没有 17 这个选项,有就代表 SDK 配对了。

Gradle 项目还有更稳的方式,在 build.gradle 里声明 toolchain:

java { toolchain { languageVersion = JavaLanguageVersion.of(17) } }

toolchain 的意思是构建时 Gradle 会去找能运行 17 的 JDK,找不到会尝试自动下载。这个声明写进项目文件后,换机器、换人开发都不会因为各自全局 JDK 版本不同而翻车。我把这个配置写进模板项目里之后,新同事加入再也没问过“为什么我这边编译报错”。

6. 一个技巧:把 JDK 17 当“绿色软件”管理,一劳永逸

最后一个技巧,也是我目前每台 Mac 上都在用的方式:利用符号链接,把 JDK 17 做成一个可随时切换的“绿色软件”,而不是绑定在某个具体版本号上。

思路是这样的:新建一个不带版本号的链接名 current,让 JAVA_HOME 永远指向 current,而不是具体版本号。以后 17.0.x 升级到新 patch 版本时,只要把链接改到新目录,所有配置都不用动。

# 将当前使用的 JDK 链接到 current ln -sfn /usr/local/java/jdk-17.0.x.jdk /usr/local/java/current # 环境变量里只写 current,不写死具体版本号 export JAVA_HOME="/usr/local/java/current/Contents/Home" export PATH="$JAVA_HOME/bin:$PATH"

配合 alias,切换 JDK 就变成一条短命令:

alias jdk17='export JAVA_HOME=/usr/local/java/current/Contents/Home; export PATH="$JAVA_HOME/bin:$PATH"' alias jdk8='export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home; export PATH="$JAVA_HOME/bin:$PATH"'

注意 alias 里必须有 export PATH 那半句,因为只改 JAVA_HOME 不改 PATH,java 命令仍会落到旧版本的 bin 目录。这两个 alias 放进 .zshrc 后,命令行切换版本就是敲一个单词的事。

这套管理方式还有另一个好处:整个 jdk-17.0.x.jdk 目录可以打包拷到另一台同架构 Mac 上,解压到相同路径,配置逻辑完全一致,没有任何系统级注册步骤。我帮同事在三台 Mac 上搭过同样的环境,全部复用这一套。从那以后我每次在新 Mac 上配 Java 环境,都强制走一遍同样的流程——解压、ln -sfn 建链接、验证 which java——三分钟完事,再也没翻过车。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 17:18:16

ReactOS:开源NT内核复刻,实现Windows二进制级兼容

1. 项目概述&#xff1a;这不是“另一个Linux”&#xff0c;而是一次对Windows兼容性边界的硬核挑战ReactOS这个名字&#xff0c;第一次听到时我下意识以为是某个React框架的衍生项目——直到在某次嵌入式设备调试现场&#xff0c;看到一位老工程师用它直接运行起一个20年前的工…

作者头像 李华
网站建设 2026/10/29 17:17:36

Linux服务器后门端口查杀与防御实战指南

1. 项目概述&#xff1a;后门端口查杀的必要性服务器运维中最让人头疼的&#xff0c;莫过于发现系统被植入了后门程序。这些恶意程序通常会开放特定端口进行远程控制&#xff0c;轻则窃取数据&#xff0c;重则沦为肉鸡。上周我处理的一台CentOS服务器就遭遇了这种情况——攻击者…

作者头像 李华
网站建设 2026/10/29 17:17:16

Codex 深度解析:从 AI Agent 原理到实战任务编排与避坑指南

1. 先搞清楚 Codex 到底是个什么东西1.1 它不是单纯的代码补全&#xff0c;而是能自己干活的 Agent很多人第一次听到 Codex&#xff0c;脑子里蹦出来的还是“代码补全工具”&#xff0c;跟早期的自动补全插件划等号。这个认知偏差如果不纠正&#xff0c;后面所有的上手操作都会…

作者头像 李华
网站建设 2026/10/29 17:16:12

DeepSeek 15天实战入门:从提问技巧到自动化工作流

简介&#xff1a;《DeepSeek人工智能平台15天从入门到精通操作手册》是一份系统化AI应用指南&#xff0c;面向办公人士、科研工作者、自媒体创作者、学生及编程爱好者&#xff0c;围绕注册登录、基础对话、文档处理与自动化、学术写作辅助、新媒体运营、学习规划及跨语言翻译等…

作者头像 李华
网站建设 2026/10/29 17:15:13

房间声学冲激响应(RIR)模拟生成:镜像源法与Python实现详解

简介&#xff1a;房间声学冲激响应&#xff08;RIR&#xff09;的模拟生成源码包&#xff0c;采用Allen与Berkley于1979年提出的镜像声源模型&#xff08;image method&#xff09;&#xff0c;将房间边界反射等效为虚拟声源&#xff0c;从而精确计算直达声与多次反射声&#x…

作者头像 李华
网站建设 2026/10/29 17:13:31

VTI介质交错网格有限差分:Matlab波场快照模拟与Thomsen参数解析

简介&#xff1a;一套面向地震勘探与地球物理研究人员的VTI介质Matlab数值模拟工具包&#xff0c;用于模拟各向异性介质中地震波传播&#xff0c;解决波场正演与可视化问题。VTI介质指纵波速度在垂直与水平方向存在差异的岩石层&#xff0c;这种各向异性普遍存在于实际地壳结构…

作者头像 李华