1. 为什么 JDK 11 依然是很多项目的首选版本
JDK 11 是 Java 生态里一个很特殊的存在。它既不像 JDK 8 那样“老而弥坚”,也不像 JDK 17、JDK 21 那样带着一堆新特性往前冲,但它恰好卡在一个非常舒服的位置上:语言特性够用、性能足够好、长期支持周期长、周边工具链兼容性成熟。很多团队在从 JDK 8 往上升级时,第一站选的就是 JDK 11,而不是直接跳到 17 或 21,原因就在这里。
我自己经手过的项目里,有做后台服务的,有做数据处理管道的,也有做桌面工具和构建脚本的。这些项目在选 JDK 版本时,考虑的点其实很一致:第一,运行稳定,不能因为 JDK 本身的问题导致线上抖动;第二,依赖库要能跟上,不能出现某个核心库只支持到 8、另一个只支持 17 的尴尬局面;第三,团队里不同人的开发环境要能统一,不能有人用 8、有人用 11、有人用 17,最后编译出来的东西行为不一致。JDK 11 在这三点上表现都很均衡,所以它成了很多项目的“最大公约数”。
从语言层面看,JDK 11 相比 JDK 8 增加了不少实用东西。比如var局部变量类型推断,写代码时不用再反复写冗长的类型名;比如HttpClient标准化,做 HTTP 请求不用再依赖第三方库;比如单文件源码直接运行,写个小工具脚本不用先编译再执行。这些特性单独看都不算惊天动地,但组合在一起,日常开发效率确实能提升一截。
从工具链角度看,JDK 11 对容器化部署的支持也比 8 好很多。JDK 8 时代,容器里跑 Java 应用经常遇到内存和 CPU 识别不准的问题,需要额外加参数去修正。JDK 11 在这方面做了改进,容器感知能力更强,配合合理的 JVM 参数,资源利用率会更好。这也是为什么很多云原生项目在选基础镜像时,会优先考虑 JDK 11 而不是 8。
当然,JDK 11 也不是没有坑。比如它移除了 Java EE 和 CORBA 相关的模块,一些老项目如果直接依赖javax.xml.bind这类包,升级到 11 之后就会报ClassNotFoundException。再比如,一些老版本的构建工具、代码生成工具、字节码增强工具,对 JDK 11 的支持并不完善,需要升级到较新的版本才能正常工作。这些问题在升级前如果没排查清楚,很容易在编译或启动阶段卡住。
所以,这篇内容不是单纯告诉你“去哪里下载 JDK 11”,而是想从实际使用的角度,把 JDK 11 的获取、安装、环境配置、多版本共存、常见问题排查这一整套流程讲清楚。无论你是刚接触 Java 的新手,还是需要给团队统一开发环境的老手,都能从中找到可以直接参考的操作步骤和避坑经验。
2. JDK 11 下载渠道与版本选择
2.1 官方渠道与常见发行版对比
JDK 11 的下载渠道其实不止一个。很多人第一反应是去 Oracle 官网找,但 Oracle JDK 从某个版本开始,商用场景需要留意授权问题。对于个人学习、开发测试,或者不想处理授权问题的团队,更常见的选择是使用开源发行版。
目前市面上主流的 JDK 11 发行版有这么几类:Oracle 官方构建、Eclipse Temurin、Amazon Corretto、Azul Zulu、Microsoft Build of OpenJDK、阿里巴巴 Dragonwell 等。这些发行版都基于 OpenJDK 源码构建,核心功能一致,区别主要在于维护策略、更新频率、附加工具和授权条款。
| 发行版 | 维护方 | 授权特点 | 适用场景 |
|---|---|---|---|
| Oracle JDK 11 | Oracle | 商用需关注授权条款 | 个人学习、已获授权的商用 |
| Eclipse Temurin | Eclipse 基金会 | 开源免费 | 通用开发、生产部署 |
| Amazon Corretto | Amazon | 开源免费 | AWS 环境、通用场景 |
| Azul Zulu | Azul | 开源免费 | 嵌入式、桌面、服务端 |
| Microsoft Build | Microsoft | 开源免费 | Azure 环境、通用场景 |
| Dragonwell | 阿里巴巴 | 开源免费 | 国内云环境、大规模服务 |
我自己的习惯是:本地开发用 Eclipse Temurin,因为它的更新节奏稳定,安装包干净,和主流 IDE 配合没什么问题;如果项目部署在特定云平台上,就优先选对应厂商的发行版,省得在基础镜像和 JDK 兼容性上折腾。
注意:无论选哪个发行版,都要确认它提供的是完整 JDK 而不是 JRE。JDK 包含编译器和调试工具,JRE 只有运行环境。做开发必须用 JDK。
2.2 版本号里的门道:11.0.x 怎么选
JDK 11 的版本号格式是11.0.x+y,其中x是补丁版本号,y是构建号。比如11.0.20+8,表示第 20 个补丁版本,第 8 次构建。补丁版本会包含安全修复和 bug 修复,所以原则上应该选最新的补丁版本。
但实际操作中,并不是越新越好。有些项目因为依赖了特定版本的字节码处理库,升级到最新的 JDK 11 补丁版后反而会出现兼容性问题。这种情况虽然不多,但一旦遇到就很头疼。我的建议是:新项目直接用最新补丁版;老项目升级时,先查一下核心依赖库的官方文档,看看有没有标注推荐的 JDK 补丁版本范围。
另外,如果你在 Windows 上开发,下载时要注意选对安装包类型。通常有.exe安装版和.zip免安装版两种。安装版会自动配置一部分环境,适合新手;免安装版解压即用,适合需要多版本共存或者不想动系统目录的情况。我一般推荐用免安装版,因为控制权完全在自己手里,卸载就是删文件夹,不会在系统里留一堆注册表项。
2.3 下载前的环境确认
在点下载按钮之前,先花一分钟确认几件事:你的操作系统是 Windows、macOS 还是 Linux;系统架构是 x64、aarch64 还是别的;磁盘上有没有足够的空间。JDK 11 安装后大概占 300MB 到 500MB,加上后续的依赖缓存和项目文件,建议至少留 2GB 以上。
如果是 Linux 环境,还要确认是 glibc 还是 musl。大多数发行版用的是 glibc,但 Alpine Linux 用的是 musl,需要专门下载对应版本。这个点很容易被忽略,下载了 glibc 版本在 Alpine 上跑,会直接报找不到动态链接库。
3. Windows 环境下 JDK 11 安装与环境变量配置
3.1 安装过程与目录选择
Windows 下安装 JDK 11,如果用的是.exe安装包,双击之后基本一路下一步就行。但有两个地方值得留意:一是安装路径,默认会放在C:\Program Files\Java\jdk-11.0.x下面,路径里有空格。有些老工具对带空格的路径支持不好,所以我会改成C:\Java\jdk-11这种没有空格的短路径。二是安装内容,安装器会问你要不要装 JRE、要不要装源码、要不要装公共 JRE。做开发的话,JDK 本身就够了,公共 JRE 可以不装,避免系统里出现多个 Java 运行时互相干扰。
如果用的是.zip免安装版,解压到你喜欢的目录,比如D:\dev\jdk-11,然后手动配置环境变量。这种方式更干净,也方便以后同时放多个 JDK 版本。
3.2 环境变量配置的完整步骤
环境变量配置是新手最容易卡住的地方。网上教程很多,但有些步骤已经过时了,照着做反而会出问题。我按自己的操作习惯,把步骤拆解一下。
第一步,打开系统环境变量设置。在 Windows 搜索框里输入“环境变量”,选择“编辑系统环境变量”,然后点“环境变量”按钮。
第二步,新建JAVA_HOME变量。在“系统变量”区域点“新建”,变量名填JAVA_HOME,变量值填 JDK 的安装目录,比如C:\Java\jdk-11。注意不要带\bin,也不要带结尾的反斜杠。
第三步,编辑Path变量。找到系统变量里的Path,点“编辑”,然后新建一条%JAVA_HOME%\bin。把它移到列表靠上的位置,避免被其他 Java 路径覆盖。
第四步,可选地设置CLASSPATH。现代 Java 项目基本不需要手动配CLASSPATH,构建工具和启动脚本会自己处理。如果非要配,就设成.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar,但我不推荐这么做,容易引起类加载冲突。
配置完成后,打开一个新的命令提示符窗口,输入java -version和javac -version。如果两个命令都能正确输出版本号,并且版本号一致,说明配置成功。如果java能用但javac不能用,通常是Path里只加了 JRE 的路径,没加 JDK 的bin目录。
提示:修改环境变量后,一定要新开命令行窗口再测试。已经打开的窗口不会自动加载新的环境变量,这是很多人以为配置失败的原因。
3.3 多版本 JDK 共存的切换技巧
开发机上同时装 JDK 8、11、17 是很常见的事。如果每次切换都要改环境变量,效率太低。我的做法是:把每个 JDK 的安装路径都记下来,然后写几个简单的批处理脚本,比如use-jdk11.bat、use-jdk8.bat,内容就是临时设置当前窗口的JAVA_HOME和Path。
@echo off set JAVA_HOME=C:\Java\jdk-11 set Path=%JAVA_HOME%\bin;%Path% echo JDK 11 activated. java -version这样在需要切换版本时,运行一下对应脚本就行,不影响系统全局配置。IDE 里也可以单独指定 JDK,比如 IntelliJ IDEA 可以在项目结构里为每个项目设置不同的 SDK,不需要依赖系统环境变量。
4. Linux 与 macOS 下的安装方式
4.1 Linux 包管理器安装与手动安装
Linux 下安装 JDK 11,最省事的方式是用包管理器。比如 Ubuntu/Debian 系可以apt install openjdk-11-jdk,CentOS/RHEL 系可以yum install java-11-openjdk-devel。包管理器会自动处理依赖和环境变量,安装完直接就能用。
但包管理器安装的版本可能不是最新的补丁版,而且安装路径比较深,不太方便手动管理。如果你需要精确控制版本,或者要在同一台机器上放多个 JDK,手动安装更合适。下载对应的.tar.gz包,解压到/opt/java/jdk-11这类目录,然后在~/.bashrc或~/.zshrc里配置环境变量。
export JAVA_HOME=/opt/java/jdk-11 export PATH=$JAVA_HOME/bin:$PATH改完之后执行source ~/.bashrc让配置生效,再用java -version验证。
4.2 macOS 下的安装与路径确认
macOS 下可以用 Homebrew 安装,命令是brew install openjdk@11。不过 Homebrew 安装的 JDK 默认不会链接到系统路径,需要手动做一下软链接,或者把JAVA_HOME指向 Homebrew 的安装目录。
另一种方式是从发行版官网下载.tar.gz包,解压到/Library/Java/JavaVirtualMachines/下面。这个目录是 macOS 识别 JDK 的标准位置,放进去之后,系统自带的java_home工具就能找到它。
/usr/libexec/java_home -V这个命令会列出系统里所有已安装的 JDK。你可以用/usr/libexec/java_home -v 11来获取 JDK 11 的路径,然后在脚本里动态设置JAVA_HOME。
macOS 上还有一个容易踩的坑:系统可能自带了一个旧版本的 Java 运行时。如果你在终端里输入java -version看到的版本不对,先用which java看看实际调用的是哪个路径下的 Java,再决定是调整PATH顺序还是做软链接。
5. 安装后的验证与基础配置检查
5.1 验证 JDK 是否正常工作
安装完 JDK 11 之后,不要急着写代码,先做几个基础验证。第一个是java -version,确认输出里有11.0.x字样。第二个是javac -version,确认编译器可用。第三个是写一个最简单的 Java 文件,编译并运行一下。
public class Hello { public static void main(String[] args) { System.out.println("JDK 11 ready: " + System.getProperty("java.version")); } }保存为Hello.java,然后执行javac Hello.java和java Hello。如果能看到版本号输出,说明 JDK 的编译和运行链路都是通的。
5.2 关键系统属性查看
有时候版本号对了,但运行行为不对,可能是因为 JDK 的安装目录、扩展目录或者安全配置有问题。可以用下面这个命令查看关键系统属性:
java -XshowSettings:properties -version它会输出java.home、java.class.path、java.library.path等信息。重点看java.home是不是指向你期望的 JDK 目录。如果指向了别的版本,说明环境变量或者PATH顺序有问题。
5.3 构建工具与 IDE 的 JDK 配置
JDK 装好了,不代表项目就能顺利编译。Maven、Gradle、IDE 都有各自的 JDK 配置。Maven 默认使用JAVA_HOME指向的 JDK,但也可以在settings.xml里指定。Gradle 可以在gradle.properties里设置org.gradle.java.home。IDE 则通常在项目设置或全局设置里单独指定 SDK。
我遇到过好几次“命令行编译通过、IDE 里报错”的情况,最后发现是 IDE 用的 JDK 和命令行不是同一个。所以装完 JDK 后,花几分钟把 IDE 和构建工具的 JDK 配置都检查一遍,能省掉很多莫名其妙的排查时间。
6. 常见问题与排查技巧实录
6.1 环境变量配置失败怎么查
环境变量配置失败的表现有很多种:java命令找不到、javac命令找不到、版本号不对、能编译不能运行。排查思路其实很固定:先确认JAVA_HOME的值对不对,再确认Path里有没有%JAVA_HOME%\bin,最后确认命令行窗口是不是新开的。
如果JAVA_HOME对了但java还是找不到,可能是Path里有其他 Java 路径排在前面。把%JAVA_HOME%\bin移到最上面通常能解决。如果java能用但javac不能用,检查一下JAVA_HOME是不是指向了 JRE 而不是 JDK。
还有一个隐蔽的问题:Windows 环境变量有“用户变量”和“系统变量”之分。如果你在用户变量里改了Path,但系统变量里也有 Java 路径,最终生效的可能是系统变量。所以改的时候要两边都看一眼。
6.2 版本冲突与“找不到 JDK”的典型场景
“找不到 JDK”这个报错在不同工具里含义不一样。Maven 说找不到 JDK,通常是JAVA_HOME没设或者设错了。Gradle 说找不到 JDK,可能是org.gradle.java.home指向了一个不存在的路径。IDE 说找不到 JDK,可能是 SDK 配置被删了或者路径变了。
还有一种情况是:系统里装了多个 JDK,但某个工具硬编码了某个路径。比如有些老版本的构建脚本会直接写C:\Program Files\Java\jdk1.8.0_xxx,你升级到 JDK 11 之后,这个路径不存在了,脚本就报错。这种问题只能去改脚本或者做目录软链接。
6.3 升级到 JDK 11 后常见的兼容性问题
从 JDK 8 升级到 11,最常见的兼容性问题有三类。第一类是 Java EE 模块移除导致的ClassNotFoundException,比如javax.xml.bind.JAXBException。解决办法是手动引入对应的依赖,比如jakarta.xml.bind-api和jaxb-impl。第二类是字节码处理库不兼容,比如老版本的 ASM、CGLIB、Javassist,需要升级到支持 JDK 11 的版本。第三类是 JVM 参数变化,比如-XX:+UseConcMarkSweepGC在 JDK 11 里虽然还能用,但已经被标记为废弃,未来版本会移除,建议换成 G1 或 ZGC。
| 问题现象 | 可能原因 | 解决方向 |
|---|---|---|
| 启动报 ClassNotFoundException | Java EE 模块被移除 | 引入对应 Jakarta 依赖 |
| 编译报字节码版本错误 | 依赖库不支持 JDK 11 | 升级 ASM/CGLIB 等库 |
| GC 日志格式变化 | JVM 日志参数调整 | 使用 -Xlog 系列参数 |
| 容器内内存识别不准 | 未开启容器支持 | 设置 -XX:+UseContainerSupport |
| 日期时间格式化异常 | 旧版日期库兼容问题 | 升级依赖或改用 java.time |
6.4 多版本共存时的路径优先级问题
多版本共存时,最容易出问题的地方是路径优先级。比如系统Path里同时有 JDK 8 和 JDK 11 的bin目录,哪个在前面就用哪个。如果你用脚本临时改了JAVA_HOME,但Path里还是旧的路径,那java命令用的还是旧版本。
我的做法是:系统Path里只放一个“默认 JDK”的路径,其他版本通过脚本临时切换。IDE 和构建工具则各自独立配置,不依赖系统Path。这样虽然多花几分钟配置,但能避免很多版本混乱的问题。
7. 给不同阶段读者的实操建议
如果你是完全新手,第一次装 JDK,我的建议是:Windows 用免安装版解压到短路径,手动配JAVA_HOME和Path,然后写一个 Hello World 跑通。不要一上来就折腾多版本共存,先把单版本跑顺。
如果你是有经验的开发者,需要给团队统一环境,建议把 JDK 安装包和配置脚本一起放进内部文档,明确版本号、安装路径、环境变量值。最好再提供一个验证脚本,新同事装完跑一下,能自动检查java、javac、JAVA_HOME是否正确。
如果你在维护老项目,准备从 JDK 8 升级到 11,建议先在本地或测试环境做一次完整构建和启动测试,重点检查 Java EE 依赖、字节码库版本、JVM 参数。确认没问题后再推到 CI 和线上。
最后分享一个我自己的小习惯:每次装完新 JDK,都会在JAVA_HOME目录下放一个version.txt,写上安装日期、版本号、下载来源。过几个月再回头看,能快速回忆起这台机器上装的是什么版本,省得再去命令行里查。这个习惯看起来不起眼,但在多机器、多版本的环境里,能省不少事。