资讯动态

OpenJDK 21在Windows x64下的安装配置与常见坑解析

发布时间:2026/10/14 13:48:09 来源:尧图企业网站定制
简介OpenJDK 21 Windows x64 是一个适用于64位Windows系统的Java开发工具包开源版本主要面向希望跟进Java最新进展的开发者、测试人员及企业技术预研团队。该版本包含编译器、运行时环境及常用工具便于在本机安装后直接体验JEP中提出的新特性同时为非LTS版本适合对稳定性要求不极端、追求新功能的场景。压缩包共484个文件约189.2MB以dll动态链接库、jmod模块文件、exe可执行程序及properties配置文件为主另含license许可信息、jfc界面配置和certs证书等结构完整基本对应JDK发布目录的标准组成。目前已有567人学习或下载资源可帮助开发者快速获得完整JDK 21工具链用于本地开发、测试最新API及构建跨版本兼容验证其开源许可与Oracle JDK接近也适合作为教学或社区协作的基础环境。1. OpenJDK 21 在 Windows x64 下的落地先厘清你到底需要什么如果你刚接触 OpenJDK 21 的 Windows x64 安装包很容易被一堆概念绕晕到底是下 zip 还是 msiJAVA_HOME 和 PATH 要不要设为什么装了 Java 8 之后再装 21 总是显示旧版本。实际上OpenJDK 21 在当前这个时间点就是适合长期使用的 LTS 版本比 17 多了虚拟线程、模式匹配、记录类这些对日常开发影响很直接的东西。这一篇不会去讲虚的从选型、下载、配置、验证到玄学排错全部按实际动手的顺序来你照着做就能在当前这台 Windows x64 机器上把 21 跑起来。2. 选型为什么是 OpenJDK 21 而不是其他版本2.1 LTS 与激进版本的取舍Java 的版本节奏现在基本是半年一个小版本、两年一个 LTSOpenJDK 21 就是继 17 之后的新 LTS。对一线研发来说LTS 最大的价值不是新特性多而是你在生产环境里能拿到足够长的维护周期出了安全漏洞修复得比非 LTS 更吃得准。很多团队还在 Java 8 上待着但 8 已经非常老了新项目如果还选 8等于自己放弃掉了语言层面好几代的能力提升。21 带来的虚拟线程是特别针对高并发 IO 场景的以前用线程池硬扛几万连接现在可以更优雅地处理。模式匹配主要在 switch 上用代码能简洁不少。还有 record 类定义数据载体的时候少写一堆 getter/setter。这些特性都不是学术概念而是在你写业务代码时真能少掉头发的东西。如果只是做一个内部工具那么 21 完全够用如果是要发布到生产21 也足够稳。非 LTS 的版本比如 18、19、20、22迭代太快同一个项目半年就要换一次除非你想尝鲜某个只在特定版本里出现的实验性特性否则没必要在上面耗时间。我一般会建议团队在 17 和 21 之间选如果已经能从 Java 8 跳出来那直接上 21不用再在 17 上过渡一轮。2.2 发行版差异官方源码构建与社区二进制包OpenJDK 本身是一套开源代码任何人都可以把自己的补丁和编译产物打成一个发行版。所以你会在网上看到各种后缀不同的 OpenJDK 21 压缩包有的带 jdk 字样有的带 jre有的还捆绑了额外的字体库或管理工具。这些发行版在实际使用上大体一致但细节不一样。最常见的选择是直接使用社区构建的二进制包。这类包一般有两种形态一是纯 zip 解压版不写注册表适合喜欢手动控制的人二是安装程序版会帮你写注册表和环境变量适合想省事的人。我个人的习惯是下载 zip 版因为安装版有时候会在你不想被污染的地方塞一个自动更新服务对于离线用户来说很烦。还有一点要留意有的二进制包在编译时启用了不同的 GC 默认策略或额外的平台优化但绝大多数场景下这种差异对业务代码透明。如果你是在做嵌入式控制或者需要把 Java 运行环境打进安装包那就要关注模块裁剪功能。21 的 jlink 能让你去掉不用的模块生成一个精简的运行镜像。所以选型时最好选标准 JDK 包而不是预打包了 JRE 的完整版因为 jlink 需要基于完整的 jmods 目录工作。后面第 6 章我会具体演示怎么裁剪。2.3 确认 Windows x64 与 arm64 的区别标题里写的是 win x64这个 x64 指的就是 Intel 64 位和 AMD 64 位那一套指令集。现在的 Windows 笔记本和台式机绝大多数都是 x64但也有少数 ARM 架构的设备比如某些新出的平板或服务器。如果你下载成了 ARM 压缩包虽然在某些系统上能转译运行但性能会打折而且 native 库经常对不上。确定架构的方式很简单在 Windows 设置里看系统类型或者命令行输入echo %PROCESSOR_ARCHITECTURE%看到AMD64就说明你是 x64看到ARM64就说明你是 ARM。还有一种情况是你其实用的是 32 位 Windows那 OpenJDK 21 基本没有官方 32 位构建了这种情况下也别折腾直接换机器或者用虚拟机。这个点很少有人提前讲但我在帮同事排查问题时就遇到过一次他下载了 arm64 包java -version都能显示但一跑 Native 访问相关代码就崩查了半天才发现是架构不匹配。另外Windows Server Core 这种精简系统没装图形环境安装版可能跑不起来这时候 zip 解压版反而更合适。所以在下载前花一分钟确认架构能省掉后续大半的为什么我的环境有问题的困惑。3. 安装与配置三种方式与 PATH 变量细节3.1 方式一用压缩包解压免安装压缩包方式是最推荐的方式因为不需要管理员权限就可以完成安装也方便随时卸载。先把下载好的 zip 包解压到一个固定的目录比如C:\jdk-21。解压后目录结构里应该能看到bin、lib、conf、jmods等文件夹没有的话说明包下错了。解压完成后需要手动设置 JAVA_HOME 和 PATH。在命令行窗口里可以先用下面这条命令做临时验证本次会话有效$env:JAVA_HOME C:\jdk-21 $env:Path $env:JAVA_HOME\bin;$env:Path java -version这段命令先给当前 PowerShell 进程设置 JAVA_HOME再把 JDK 的 bin 目录加到 PATH 最前面最后执行java -version。如果输出类似openjdk version 21 ...说明解压包本身没有损坏。注意这里用的是$env:语法如果你打开的是 cmd那么对应的写法是set JAVA_HOMEC:\jdk-21和set Path%JAVA_HOME%\bin;%Path%。临时设置只在当前窗口有效关掉就没了要想永久生效得用后面的setx或图形界面。zip 方式最大的坑点在于你不能直接把包解压到桌面或某个中文目录下否则后面跑某些依赖原生路径的工具时会因为空格和中文编码出问题。我一般会建议解压到分区根目录下的纯英文路径比如D:\dev\jdk-21避免后续所有麻烦。3.2 方式二用安装程序走图形界面安装程序方式适合不常在命令行操作的同事。安装包的格式通常是 msi 或 exe双击后跟着向导下一步。安装程序会默认把 JDK 装到C:\Program Files\下面并且自动帮你配置好 JAVA_HOME、PATH以及注册表里的 Java 信息。这个方式省事但也有隐患。Program Files 目录有空格虽然大部分工具能处理但个别老的脚本会把路径按空格拆开导致报找不到 java。更关键的是安装程序会偷偷把java.exe、javaw.exe等文件复制到C:\Windows\System32目录里这样做会让你的环境变量顺序变得非常混乱后面一旦装了其他版本就可能出现我怎么改 PATH 都没用的状况。所以如果你用了安装程序安装完成后最好检查一下C:\Windows\System32\java.exe是否真的存在如果存在我建议直接把它删掉删除前确认没有其他程序依赖它。安装过程中如果让你选择安装哪些组件一般只勾选 JDK 和 JavaFX 相关的即可公共 JRE 那个选项没必要选因为 JDK 里面就包含了运行时。装完之后验证方式同 3.1在任意新开的命令行里执行java -version。3.3 方式三用包管理器命令行安装Windows 10 以上的系统自带 winget可以用它搜索并安装 Java。先打开 PowerShell执行搜索命令winget search openjdk这个命令会把所有名称里带 openjdk 的可用包列出来你会看到不同构建方、不同版本的内容。因为不能直接确定具体的包 ID一般需要根据输出里的版本号选择 OpenJDK 21 对应的那一行然后执行winget install --id 包ID --version 21.0.x版本号以实际搜索结果为准。winget 安装本质上还是调用安装程序或解压脚本装完之后同样需要新开一个命令行窗口才能让环境变量生效。用包管理器的好处是以后升级可以一条命令搞定但坏处是它管理的安装路径比较深而且不同包管理器之间可能互相不认账。如果你之前用 choco 装过一个 Java现在用 winget 装另一个两个就可能打架。所以建议一开始就只选一种包管理器别混着来。安装完成后同样用java -version验证。3.4 配置 JAVA_HOME 与 PATH 的完整步骤不管用哪种方式安装最终的配置核心都是 JAVA_HOME 和 PATH。JAVA_HOME 指向 JDK 的根目录PATH 里需要包含%JAVA_HOME%\bin。永久配置推荐使用setx命令setx JAVA_HOME C:\jdk-21 setx PATH C:\jdk-21\bin;%PATH%第一条命令把 JAVA_HOME 写入用户环境变量第二条把 bin 目录追加到 PATH 的最前面。注意这里有个坑setx PATH ...如果直接引用已有的%PATH%会把系统变量的内容带过来可能导致之后重复运行命令时 PATH 被无限放大。更稳妥的做法是去图形界面里改右键“此电脑” - 属性 - 高级系统设置 - 环境变量在“用户变量”里新建 JAVA_HOME然后在 PATH 里点“新建”追加一行%JAVA_HOME%\bin。图形界面能避免 setx 的截断风险也能让你直观看到当前的变量列表。修改完环境变量后所有已打开的命令行窗口都必须关闭再重新打开不能直接在当前窗口里看到新配置因为 Windows 环境变量的广播机制不会主动通知已经启动的进程。还有一点如果你同时安装了 32 位和 64 位的 Java这个 PNG 会自动发生版本冲突所以尽量只保留一个 JDK 在 PATH 里。4. 验证与环境检查从 java -version 到编译运行第一个程序4.1 命令行验证与常见输出解读配置完成后新开一个 cmd 或 PowerShell依次执行两条命令java -version javac -version正常情况下你会看到类似下面的输出openjdk version 21.0.2 2024-01-16 OpenJDK Runtime Environment (build 21.0.213) OpenJDK 64-Bit Server VM (build 21.0.213, mixed mode, sharing)第一行openjdk version 21.0.2是核心信息其中的2024-01-16是构建日期代表这是这个版本某个时间点的快照。第三行的64-Bit说明你用的是 64 位 VM如果是 32 位会显示32-Bit。mixed mode表示解释器和即时编译器混合执行sharing表示类数据共享功能已经开启。如果你看到的是java version 1.8.0_xxx或者javac不是内部或外部命令说明你当前环境还没指向 21。javac -version应该输出javac 21.0.x如果 java 正常但 javac 报错多半是 PATH 里只加了某个运行时路径而没有加 JDK 的 bin。很多初学 Java 的人只装了 JRE 没装 JDK就会出现能运行 class 文件但不能编译的情况。还有一点java -version的-version是标准参数--version也行差别不大。4.2 编写并编译一个最简单的 Java 类环境就绪后先建一个工作目录然后写一个最简单的类来跑通编译和执行。在命令行里用记事本创建Hello.javamkdir demo cd demo notepad Hello.java文件内容import java.time.LocalDate; public class Hello { public static void main(String[] args) { System.out.println(Hello, OpenJDK 21); System.out.println(Today: LocalDate.now()); } }注意文件名必须和 public 类名一致保存时编码选择 UTF-8因为这个类里用了中文字符串。然后回到命令行javac Hello.java java Hello第一行javac Hello.java会编译生成Hello.class文件第二行java Hello运行它。如果你看到输出和预期一致说明整个链路已经通了。这里有个很容易犯的错误运行java Hello时不需要加.class后缀也不需要写全路径类名就够了。如果你在classpath里放了奇怪的东西可能会干扰类加载但正常情况下不设置 classpath 也能跑。对于新手来说编译失败最常见的原因是文件编码不对。如果出现了类似 编码 GBK 的不可映射字符 的错误说明你的源文件是 ANSI 编码而 javac 默认读取的是平台默认编码解决办法后面避坑章会专门讲。4.3 参数调整堆内存与 GC 选择21 默认使用 G1 垃圾回收器对大多数应用来说够用。但你如果跑的是内存密集型程序可能需要显式设置堆大小。举个例子java -Xms256m -Xmx2g -XX:UseG1GC -XX:MaxGCPauseMillis200 Hello这里-Xms256m表示初始堆大小 256 MB-Xmx2g表示最大堆 2 GB-XX:UseG1GC强制指定 G1-XX:MaxGCPauseMillis200是 G1 的软目标停顿时间。注意这些参数要和java命令放在一起放在类名后面会被当成程序参数传给main。调试的时候建议加-Xlog:gc*来看 GC 日志21 里老式子参数-XX:PrintGCDetails已经废弃了要用新的统一日志体系。还有一个很实用的参数是-XX:ShowCodeDetailsInExceptionMessages但 21 里这个默认也差不多了。对于排查类加载问题可以用-verbose:class它能列出加载了哪些类和来自哪个 jar对于依赖冲突的排查极其有用。这些参数都是 JVM 层面的不会改变你的程序逻辑但调对了能显著减少莫名其妙的卡顿和 OOM。4.4 与旧版本共存时的版本切换很多机器上同时装了 Java 8 和 Java 21这时 PATH 里谁靠前谁就生效。最干净的切换方式是不去修改系统环境变量而是写一个简单的切换脚本。在 PowerShell 里可以这样做function jdk21 { $env:JAVA_HOMEC:\jdk-21; $env:Path$env:JAVA_HOME\bin; ($env:Path -replace C:\jdk-8[^;]*;,); java -version } function jdk8 { $env:JAVA_HOMEC:\jdk-8; $env:Path$env:JAVA_HOME\bin; ($env:Path -replace C:\jdk-21[^;]*;,); java -version }这里先用$env:JAVA_HOME切换根目录然后用-replace把另一版本在 PATH 里的那一段移除再在最前面插入当前版本的 bin。注意正则中[^;]*匹配无非分号字符的任意字符用来覆盖可能的路径变体。这个函数写到 PowerShell profile 里以后每次新开窗口就能直接调用jdk21或jdk8。这种方法比去图形界面改 PATH 快得多也不容易手误删错。还有一种方案是使用 IDE 里的项目级 JDK 设置比如现在主流 IDE 都可以给每个项目单独选择 JDK 版本这样 IDE 内部的编译和运行不受系统 PATH 影响但命令行下还是以环境变量为准。5. 避坑与排查OpenJDK 21 在 Windows 上的 5 个典型坑5.1 坑一java -version 显示旧版本现象明明装好了 OpenJDK 21也设置了 JAVA_HOME但一运行java -version还是显示1.8.0_xxx。原因绝大多数情况是 PATH 里旧版本的 bin 目录排在新版本前面Windows 按顺序查找可执行文件先找到哪个就用哪个另一个可能原因是系统目录下存在残留的java.exe被优先匹配。还有可能是你的终端没有重新启动环境变量还是旧进程里的。解决先打开新命令行执行where java它会列出所有能被找到的 java.exe 路径按顺序从上到下就是最终生效的优先级。如果发现旧版本路径在前面调整 PATH 顺序如果发现C:\Windows\System32\java.exe排在前面直接删除它或重命名并确认 JAVA_HOME 已经指向新版本。之后重新开窗口验证。5.2 坑二找不到或无法加载主类现象用java Hello运行编译好的 class 文件时报错错误: 找不到或无法加载主类 Hello。原因这个错误通常不是 JVM 问题而是类名拼写不一致或 class 文件不在当前搜索路径下。还有一种情况是源文件里定义了 package比如package com.demo;而你在类文件所在目录运行java Hello必须改成java com.demo.Hello。另外如果你编译时加了-d参数把 class 输出到别的目录而当前路径不对也会找不到。解决先用dir *.class确认 class 文件存在且和类名一致区分大小写Windows 不区分大小写但 Java 区分。如果有包名在包结构根目录运行全限定类名比如java com.demo.Hello。如果你不确定 class 文件的包结构可以用javap查看类信息但最简单的是不要乱建包。我见过很多人把public class Hello写成public class hello文件名也对不上一编译就报错这种低级问题先检查类名和文件名是否一致。5.3 坑三编码 GBK 导致乱码现象编译时报错误: 编码 GBK 的不可映射字符或者运行后控制台输出中文变成乱码。原因Windows 中文系统默认编码是 GBK而你的 Java 源文件保存成了 UTF-8javac 默认按照平台编码读取文件两者不一致导致解析失败。运行时的乱码则是控制台代码页和 JVM 输出编码不匹配造成的。解决编译时显式指定编码javac -encoding UTF-8 Hello.java运行前在 PowerShell 里执行[Console]::OutputEncoding [System.Text.Encoding]::UTF8或者在 Java 代码里用System.out.println时确保数据本身正确。还有一种办法是在JAVA_TOOL_OPTIONS里加上-Dfile.encodingUTF-8但这会全局影响所有 Java 应用不太推荐。最持久的方法是编辑源文件时统一用 UTF-8 保存并且 IDE 里把项目编码设为 UTF-8命令行编译时手动附上-encoding UTF-8。这个问题在我刚转 Java 时遇到过后来习惯性地在所有 javac 命令里带上编码参数再也没翻过车。5.4 坑四jlink 生成自定义运行时后模块缺失现象使用 jlink 裁剪出一个精简运行时后运行自己的程序提示模块 javafx.control 不存在或者NoSuchModuleException。原因jlink 默认会根据你提供的模块和--add-modules参数分析依赖但分析不出来反射调用或动态加载的类。比如代码用了反射去加载某个模块里的类jlink 不会知道这个依赖于是裁剪时把这些模块去掉了。解决在 jlink 命令里显式使用--add-modules把需要的模块加进去或者用--bind-services绑定服务类。比如你的程序用到了 java.xml 和 javafx.graphics就写上--add-modules java.xml,javafx.graphics。还有一招是先用jdeps --ignore-dependency分析依赖把分析结果作为 jlink 的输入。如果程序里存在强烈依赖反射的场景最简单的后悔药是保留整个jmods目录别过度裁剪。我在一个模拟项目里为了省空间把模块裁到只剩 java.base结果程序运行到一半崩了后来加上--add-modules java.sql才稳定。5.5 坑五环境变量修改后不生效现象运行 setx 后重新打开命令行echo %JAVA_HOME%还是旧的或者 PATH 里没有新加的那一项。原因setx 写入的是注册表但当前已经打开的所有进程包括 explorer.exe都还持有旧环境块另外 setx 对变量长度有 1024 个字符的限制如果 PATH 太长写入会静默失败。解决首先确认是否用管理员权限运行其次用图形界面打开环境变量窗口看用户变量和系统变量里 JAVA_HOME 是否已经写入。如果写入正确但新窗口看不到说明 shell 没有重新加载环境块可以重启 explorer 或者直接注销重新登录。PATH 过长时清理掉一些不用的路径然后把 JDK bin 放在用户变量的 PATH 里而不是系统变量的 PATH 里能避免被其他长期路径挤压。还有一个很隐蔽的点如果你用的是 PowerShell总是去执行$env:Path ...这种命令那只是改当前会话并不会持久化只有 setx 和图形界面才是永久的。区分临时和持久这两个概念这类问题基本不会再困扰你。6. 进阶玩法用 jlink 裁剪一个最小运行时6.1 jlink 与模块化的关系OpenJDK 21 自带的 JDK 体积通常在 300MB 左右其中包含大量你可能永远用不到的模块比如 JavaFX、JVMCI、Nashorn 等。如果你要做的是一个微服务或一个小工具把这个 JDK 原样打包给别人显然太臃肿。jlink 就是解决这个问题的工具它能把模块化 JDK 变成一个只包含必要模块的精简运行镜像生成的目录里自带 bin、lib、conf可以单独分发。使用 jlink 的前提是你有一个模块化的程序或者说你至少清楚自己的程序依赖哪些模块。如果你的程序是传统的 classpath 应用jlink 也能用但需要通过--add-modules把所有模块列出来。21 里的 jlink 位于 JDK 的 bin 目录下不用额外安装。6.2 为一个简单程序裁剪运行时假设你已经编译好了Hello.jar里面只有一个依赖java.base的程序。先用 jdeps 分析依赖jdeps --ignore-missing-deps Hello.jarjdeps 会输出这个 jar 用到的所有模块。然后按依赖生成运行时jlink --module-path C:\jdk-21\jmods --add-modules java.base --output C:\minimal-jre这里--module-path指向 JDK 的 jmods 目录--add-modules java.base表示只添加基础模块--output指定生成目录。生成后运行程序C:\minimal-jre\bin\java -jar Hello.jar如果程序只用到了java.base这个运行时可能只有 40MB 左右比原 JDK 小了很多。如果程序用了java.sql或java.net.http就需要把这些模块也加到--add-modules后面注意模块名要严格按照 jdeps 输出的大小写比如java.sql不是java.sq。为了保险可以一次性加上所有被依赖的非 java.base 模块稍微牺牲点体积换取稳定性。6.3 验证裁剪结果与最终建议裁剪完的目录里有一个release文件可以用记事本打开查看版本信息。同时建议在目标机器上跑一遍C:\minimal-jre\bin\java -version和你的核心用例因为模块缺失往往在启动后才暴露比如反射触发 NoClassDefFoundError。从我自己的经验来看jlink 适合把一个几百兆的 JDK 压成适合分发的运行时但千万别为了几十 MB 的空间去做过度裁剪否则运行到特定业务路径时崩了排查成本远超那点空间收益。从那以后我每给客户发一个裁剪运行时都会强制跑一遍完整的冒烟测试除了功能用例还要扫一遍代码里的反射调用清单。希望这套流程能帮你在 Windows x64 上把 OpenJDK 21 用得更顺手。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑