简介:JDK 23面向Windows 64位的二进制压缩包,专供需要在64位Windows系统上搭建Java开发环境的开发者使用,可直接解决从JDK版本选择、下载到本地安装配置的常见问题。压缩包共425个文件,涵盖dll动态库、jmod模块描述、javac/java等exe工具,以及license、copyright等授权文件,并包含证书库、JVM配置等辅助文件,整体约228.77MB,解压后即可获得一套完整JDK组件。已有240人学习下载,对Java初学者快速入门、中高级开发者升级工具链,以及研究JVM运行机制的人员均有参考价值。包内集成JVM运行时和Java类库,配置后可调用javac编译源码、由JVM执行字节码,也可使用javadoc、jar等工具生成文档和打包发布,还能体验JDK 23带来的新特性与性能优化;同时借助jmod文件可直接了解模块化结构,结合证书库与配置工具可快速排查环境问题,帮助开发者在项目中保持较新的技术栈。
1. jdk-23-windows-x64-bin.zip:先想清楚三件事再解压
拿到一枚jdk-23-windows-x64-bin.zip,第一反应通常是解压、配置、跑java -version,然后收工。但这个压缩包背后藏着一个版本决策:JDK 23 是 2024 年 9 月发布的非 LTS 版本,下一个长期支持版本要到 JDK 25。你把它装到 Windows x64 开发机上,意味着接下来半年要跟着小版本更新走,或者明年再升一次。这不是一个“装完就跑”的活儿,它牵涉到 JAVA_HOME 指向谁、PATH 里旧版藏在哪、依赖库支不支持、要不要加--enable-preview。全文就围绕这三件事展开:装之前怎么选、装的时候怎么配、装完以后怎么验证和避坑。
2. 从 zip 压缩包到能跑 javac:JDK 23 在 Windows x64 的安装与验证
2.1 解压到哪个目录:zip 版与安装版的选择
jdk-23-windows-x64-bin.zip是官方发布的纯二进制压缩包,不包含安装向导。和 Windows 上常见的.exe安装版相比,zip 版最大的优势是“绿色”:不写注册表、不创建卸载项、不往系统目录塞文件。对于开发者来说,这意味着多版本共存时,一个目录就是一个 JDK,删掉目录就等于卸载。
我一般把 JDK 统一放到一个不带空格的根目录下,比如D:\dev\jdk。很多脚本和构建工具对带空格的路径处理得很粗糙,虽然现代工具大多能处理,但没必要给自己埋雷。
| 对比项 | zip 压缩包 | 安装向导版 |
|---|---|---|
| 安装位置 | 解压到任意目录 | 默认写进系统目录 |
| 注册表 | 不写 | 会写 |
| 多版本共存 | 目录一换就行 | 要处理卸载和升级 |
| 自动更新 | 无 | 有提示 |
| 适合场景 | 开发机、CI、脚本化 | 单机嫌麻烦的用户 |
在 Windows 10 1803 之后的系统上,可以用自带的tar命令解压,不需要额外装解压软件:
mkdir D:\dev\jdk tar -xf jdk-23-windows-x64-bin.zip -C D:\dev\jdk dir D:\dev\jdk-C参数指定解压目标目录,解压后应该得到一个名为jdk-23的子目录。dir看一下目录结构,确认bin、conf、lib、jmods这些目录都在。jmods是模块化 JDK 特有的目录,后面做jlink自定义运行时要从这里取模块。确认无误后,下一步就是环境变量。
2.2 JAVA_HOME 与 PATH:两条环境变量决定成败
安装完 JDK,最常犯的错是把 PATH 配了、JAVA_HOME 没配,或者反过来。很多构建工具和 IDE 通过 JAVA_HOME 定位 JDK,而命令行通过 PATH 找java.exe,两条缺一不可。
我用 PowerShell 的 .NET API 来配置,而不是setx。setx有个出名的问题:环境变量值太长会被截断,而且它操作的是注册表里的原值,经常把 PATH 写坏。
# 设置用户级 JAVA_HOME [Environment]::SetEnvironmentVariable("JAVA_HOME", "D:\dev\jdk\jdk-23", "User") # 把 bin 目录追加到用户 PATH $oldPath = [Environment]::GetEnvironmentVariable("Path", "User") [Environment]::SetEnvironmentVariable("Path", $oldPath + ";%JAVA_HOME%\bin", "User") # 刷新当前 PowerShell 会话,避免重开终端 $env:JAVA_HOME = "D:\dev\jdk\jdk-23" $env:Path = "D:\dev\jdk\jdk-23\bin;" + $env:Path三个参数说明一下:SetEnvironmentVariable的第三个参数"User"表示只修改当前用户的环境变量,不需要管理员权限,也不会影响系统其他账户。PATH 里追加的是%JAVA_HOME%\bin而不是写死路径,这样以后切换 JDK 版本时只改 JAVA_HOME 一处就行。最后两行刷新当前会话,是为了立刻验证,不用重开终端。然后验证:
java -version javac -version where javawhere java这条命令很关键,它列出系统实际能找到的所有java.exe路径及顺序。如果 PATH 里某个旧 JDK 的 bin 目录排在前面,java -version命中的就是旧版本。这个命令是排查“版本不对”的第一步,后续第 5 章里还会用到。
2.3 第一次编译:javac 与 java 的最小验证
环境变量配好之后,写一个最小程序验证编译和运行链路。我习惯先跑一个能输出 JDK 版本信息的类,这样既能验证环境,又能确认运行时版本。
public class FirstRun { public static void main(String[] args) { System.out.println("JDK version: " + System.getProperty("java.version")); } }javac FirstRun.java java FirstRunjavac FirstRun.java编译出FirstRun.class,java FirstRun启动 JVM 并执行main方法。JDK 23 默认把源版本和目标字节码版本都设为 23,所以不用加任何参数。命令行看到输出的版本号是23开头就说明链路通了。如果这里中文乱码,先不用慌,那是 Windows 控制台代码页的问题,不是环境变量配错了,具体的处理放到第 5 章。
3. JDK 23 新特性速览:值不值得从 21 升到 23
3.1 非 LTS 版本的节奏:半年窗口与下一个 LTS
JDK 的版本节奏是每半年一个功能版本,时间点固定在每年 3 月和 9 月。奇数版本号如 23、25,如果落在偶数版本之后,通常被规划为“下一个 LTS 的过渡版”。JDK 21 是 2023 年 9 月发布的 LTS,JDK 25 会在 2025 年 9 月成为下一个 LTS,JDK 23 正好卡在中间。
这意味着什么?JDK 23 的官方支持窗口只有半年左右,在 JDK 25 发布前,你只能拿到 JDK 23 的几个小版本更新,之后就要么升到 25,要么留在 23 裸奔。对个人开发和学习来说,这个窗口完全够用;对生产环境来说,如果业务系统没有特别需要 23 的特性,在 21 上多待一年是更稳的选择。那些“升到 23 就不用动了”的念头,是版本管理上最危险的想法。
3.2 值得试的三个新特性:Markdown 注释、模块导入、灵活构造器
JDK 23 有一项正式特性和多项预览特性值得关注。正式特性是 Markdown 文档注释,它让 javadoc 支持用 Markdown 语法写文档注释,比传统 HTML 标签在源码里写文档要清爽得多。
/// 计算两个数的和 /// /// 参数: /// - a 第一个操作数 /// - b 第二个操作数 /// /// 返回: a 与 b 的和 public static int add(int a, int b) { return a + b; }注意这里用的是///而不是传统的/**。JDK 23 里///开头的注释会被 javadoc 解析为 Markdown,支持列表、链接、代码块等语法,生成的文档页面也会比纯文本更易读。这是正式特性,编译和运行都不需要额外开关。
第二个值得看的是模块导入声明。传统的import java.util.List;要一行行写,模块导入可以直接把整个模块的公共 API 引进来。
import module java.base; public class ModuleImportDemo { public static void main(String[] args) { System.out.println("模块导入声明"); } }import module java.base;一次导入java.base模块下所有公共包,省去几十行 import 是可能的。但它是预览特性,编译和运行都必须加参数:
javac --release 23 --enable-preview ModuleImportDemo.java java --enable-preview ModuleImportDemo第三个是灵活构造器主体。JDK 23 之前,子类构造器里调用this()或super()之前不允许写任何语句,导致参数校验只能写在静态方法里。JDK 23 允许在this()之前先执行语句,比如先校验参数、再调用兄弟构造器。
public class Demo { private final int x; public Demo(int x) { if (x < 0) { throw new IllegalArgumentException("x 必须是非负数"); } this.x = x; } }这段代码在旧版本 JDK 里编译不过,JDK 23 用预览开关编译它就没问题。老实说,这个特性解决的是语法限制问题,不算刚需,但写参数校验时确实舒服。
| 特性 | 状态 | 是否要 --enable-preview |
|---|---|---|
| Markdown 文档注释 | 正式 | 否 |
| 模块导入声明 | 预览 | 是 |
| 灵活构造器主体 | 预览 | 是 |
预览特性和正式特性最大的区别是:预览特性可能在后续版本里调整甚至移除,生产环境用起来要谨慎。我的态度是:正式特性放心学,预览特性当着“预研”来玩,真正落入项目前先确认对应依赖库是否支持。
3.3 判断是否升级的三个问题
升不升 JDK 23,问三个问题就够。第一,项目依赖的三方库、框架、构建插件是否声明支持 JDK 23。很多库在 JDK 发布前只有测试版,正式支持往往滞后一两个月。第二,你的团队能不能承受半年一次的小版本升级。如果能用脚本自动切换 JDK 并跑完整测试,升级成本就低;如果全靠手工改环境变量,那就别折腾。第三,上面说的新特性中,有没有哪个能直接解决你当下的痛点。Markdown 注释对文档维护有帮助,模块导入对大型项目能省些 import,但如果没有痛点,升级就是纯消耗。
某开发者的做法值得参考:先在模拟项目X里用 JDK 23 编译、测试、打包,跑一星期,记录遇到的所有警告和兼容性问题,再决定要不要把真实项目切过去。这个模拟项目不需要很大,只要覆盖真实项目的依赖范围就够了。
4. 多版本共存与切换:同一台 Windows 上的 JDK 21/23 管理方案
4.1 目录命名与环境变量的关系
开发机上同时存在 JDK 21 和 JDK 23 是常态:项目 A 还在用 21,项目 B 想试试 23。zip 包的好处在这里体现出来,每个 JDK 就是一个独立目录,命名时带版本号是基本要求。
我习惯这样规划目录:
D:\dev\jdk\jdk-21.0.5 D:\dev\jdk\jdk-23目录名里不带空格、不带特殊字符,大小写统一。切换版本时只需要把 JAVA_HOME 指到对应目录,PATH 里的%JAVA_HOME%\bin会自动跟随,不用改 PATH。这是所有多版本管理方案的基础。
4.2 切换脚本:一条命令换 JDK 版本
手动改环境变量太慢,写一个切换脚本更省事。Windows 下可以用批处理,也可以用 PowerShell,我两种都留着。
@echo off rem 用法: set-java.bat 21 或 set-java.bat 23 set "JAVA_HOME=D:\dev\jdk\jdk-%1" set "PATH=%JAVA_HOME%\bin;%PATH%" java -versionparam([string]$ver = "23") $env:JAVA_HOME = "D:\dev\jdk\jdk-$ver" $env:Path = "$env:JAVA_HOME\bin;" + $env:Path java -version两个脚本的核心逻辑一样:根据参数拼出 JDK 目录,覆盖当前会话的 JAVA_HOME 和 PATH,然后输出版本信息做确认。注意脚本只改变当前终端窗口的环境变量,新开的终端还是会读系统环境变量里的 JAVA_HOME,这其实是刻意为之——脚本切换只影响当前终端,不会污染全局配置,也不会影响其他正在运行的程序。
4.3 用 --release 锁字节码版本,防止部署环境出问题
多版本切换最大的隐患不是切错 JDK,而是用 JDK 23 编译出来的 class 文件拿到 JDK 21 的运行时跑。class 文件的主版本号对不上会直接报UnsupportedClassVersionError,这个错误不报具体行数,容易让人一头雾水。
--release参数能同时锁定源版本、编译器 API 和字节码目标版本。用 JDK 23 编译,但指定--release 21,生成的 class 就能在 JDK 21 上运行:
javac --release 21 Demo.java javac --release 17 Demo.java--release和老的-source/-target参数不是一个东西。-source和-target只控制语法和 class 文件版本,不管你调用的 API 是哪个版本的,所以经常出现“编译通过、运行报错”的情况。--release连 JDK API 一起锁住,编译器不会让你用到比目标版本更新的 API,这是 CI 里应该统一使用的参数。
如果需要给某个应用做一个精简运行时,用jlink是替代旧 JRE 的唯一正规方案。JDK 9 之后安装版不再附带独立 JRE,但你可以自己生成:
jlink --module-path "%JAVA_HOME%\jmods" ^ --add-modules java.base,java.logging,java.sql ^ --output D:\runtime\myapp-runtime--module-path指向 JDK 自带的 jmods 目录,--add-modules列出应用实际用到的模块,--output指定生成目录。生成的运行时比完整 JDK 小不少,只包含列出的模块,适合打包给桌面应用用。模块列多了体积变大,列少了运行时报错,需要结合应用的模块依赖来确定。
5. jdk-23-windows-x64-bin.zip 安装后的五个常见坑
5.1 改了 JAVA_HOME,java -version 还是旧版本
现象:环境变量里 JAVA_HOME 已经指向D:\dev\jdk\jdk-23,新开一个终端窗口运行java -version,显示的却是 17。
原因:PATH 里有两条 JDK 路径,旧的 bin 目录排在%JAVA_HOME%\bin前面。Windows 从左到右查找可执行文件,先找到旧的就用旧的。还有一种可能是 C:\Windows\System32 里藏着一个java.exe,这是某些软件自带运行时塞进去的。
解决:先跑where java看命中顺序,会列出所有java.exe的完整路径。然后把 PATH 里旧的 JDK bin 删掉,或者把%JAVA_HOME%\bin整体移到最前面。改完记得重开终端,不要拿当前已经加载了旧环境变量的窗口验证。
5.2 解压路径带空格引发的连锁反应
现象:JDK 解压到D:\Program Files\jdk-23,IDE 里编译运行都正常,但脚本和命令行工具偶尔报找不到java,或者路径被截断。
原因:很多脚本拼接 JAVA_HOME 时没有加引号,路径里的空格把命令拆成了多段。IDE 有自己的路径处理逻辑所以没事,但脚本和 CI 工具对空格依然敏感。
解决:把 JDK 放到无空格的纯英文路径,这是最省事的办法。Windows 用户目录下那些带空格和中文的路径,建议都不要放 JDK。如果已经装在带空格的路径里,趁早搬走,后面省下的时间远超搬运成本。
5.3 控制台中文输出乱码
现象:System.out.println("中文")在 Windows 控制台输出乱码,在 IDE 的控制台输出正常。
原因:JDK 18 起默认文件编码改成 UTF-8,源码和 String 内部都是 UTF-8。Windows 中文版控制台默认代码页是 936(GBK),终端用 GBK 去解码 UTF-8 的字节,自然就是乱码。
解决:临时做法是在运行命令里加-Dfile.encoding=UTF-8,更彻底的是把控制台切到 UTF-8 代码页:
chcp 65001 java FirstRunchcp 65001把当前控制台代码页切换到 UTF-8。但注意,这只影响当前终端窗口,新开一个窗口又回到 936。代码层面最好的做法是不要在main里直接用平台默认编码做 IO,字符串写入文件或网络流时显式指定StandardCharsets.UTF_8,这才是根治。乱码这种事,看着像玄学,实际就是编码不匹配,顺着这条线排查不会翻车。
5.4 老项目切到 JDK 23 启动直接报错
现象:项目从 JDK 17 切到 23,启动时抛NoClassDefFoundError或者IllegalAccessError。
原因:老项目可能依赖了已移除的模块,或者通过反射访问了 JDK 内部的非公开 API。JDK 对强封装的限制逐版收紧,JDK 23 上,跨模块反射访问内部包默认被拒绝,报错信息里通常会明确指出哪个包被拒绝。
解决:应急手段是加--add-opens放行指定的包:
java --add-opens java.base/java.lang=ALL-UNNAMED DemoApplication--add-opens让java.base模块里的java.lang包对未命名模块开放反射访问。这是治标不治本的办法,堆多了会让启动命令又臭又长,而且某些商业库的文档里直接写着不支持新版本 JDK。根治方案是给项目做一个依赖升级,找出那些用了 JDK 内部 API 的库,换掉或升级到支持 JDK 23 的版本。这一步没捷径,只能一个个排除。
5.5 官方发行版和社区开源构建版的许可差异
现象:某公司计划把 JDK 23 打进内部基础镜像,给所有项目统一用,法务说许可需要确认,不能直接打包。
原因:官方发行版提供“无费用条款”的许可,开发、测试、内部运行没问题,但把 JDK 打包进镜像再分发时,要按照条款逐项核对使用场景。很多团队只看了下载页的“免费”字样,没细看条款适用范围。
解决:开发机和内部服务器的常规运行直接用官方版没问题。需要构建基础镜像、对外分发、嵌入产品的时候,换社区开源构建版本,或者让负责人把条款过一遍。不要因为“一直这么用没事”就忽略这个差异,等镜像被外部客户拿到,再发现许可问题就晚了。
6. 装好后第一件事:用自带工具给新 JDK 做一次“体检”
拿到新 JDK,第一件事不是写 Hello World,而是看它到底用了哪些默认参数。JDK 23 的默认值和 17 有很多细微差别,不确认就直接上生产,等于把一个黑匣子丢进线上环境。
java -XshowSettings:all -version-XshowSettings:all会打印系统属性、VM 配置、内存设置、文件编码等全部默认值,-version紧接着输出版本信息。我看到的关键检查点有三个:文件编码是不是 UTF-8、默认堆大小是多少、GC 是哪个。JDK 23 默认用 G1,堆大小按物理内存比例算,容器里要确认MaxRAMPercentage是否生效,这个参数直接决定你的 Java 进程能不能看见容器内存上限。
jcmd 9876 VM.version jcmd 9876 VM.flagsjcmd是诊断运行中 Java 进程的官方工具。9876是被诊断进程的 PID,VM.version看 JDK 版本,VM.flags看实际生效的 JVM 参数。注意它输出的是“生效值”,不是启动命令里的原始参数,很多参数没有显式写在命令里,但会被 JVM 按默认值补全,这里能看到最终状态。这个工具适合排查“为什么启动参数改了但没生效”这类问题。
体检完如果一切正常,我会把这些输出存一份到项目文档里,作为当前环境的基线。以后有人改环境、动参数、升级 JDK,拿出来对比就知道哪里变了。这个习惯帮我省下了好几次半夜排查环境差异的时间。希望帮到你。
本文还有配套的精品资源,点击获取