
JDK这东西装起来不难难的是“装对”和“卸干净”。很多人在电脑上折腾Java环境问题往往不是出在安装步骤而是出在卸载不彻底或者版本混用。旧版本残留的注册表项、环境变量里残留的路径、C盘里散落的Java目录这些都有可能让新装的JDK“带病上岗”出现java -version没反应、IDE识别不到SDK、明明配好了环境变量一开新终端又失效之类的怪问题。这篇就把JDK的卸载与安装从头到尾捋一遍覆盖Windows、macOS、Linux三种系统重点讲Windows下最容易踩坑的卸载清理、版本选择、环境变量配置和排查思路。适合刚入门Java的小白也适合帮同事救火、给服务器换环境的运维老手。看完能自己动手把一台机器的JDK彻底重置成干净可用的状态。1. 动手之前JDK版本这么多到底该装哪一个1.1 先分清JDK和JRE的关系别再搞混很多教程一上来就让你装JDK但没解释为什么。这里先花两分钟说透。JDKJava Development Kit是给开发者用的工具包里面包含了编译Java源码的javac、打包用的jar、生成文档的javadoc以及一个叫JREJava Runtime Environment的运行时环境。JRE只负责跑Java程序不含编译工具。如果你只是跑别人写好的.jar包或者.class文件装JRE就够了。但只要你写哪怕一行Java代码就必须装JDK。现在Oracle已经不再单独发布JRE安装包JDK里默认自带运行时所以你只用装一个JDK即可。从JDK 9开始安装目录结构也变了以前JDK目录下有个独立的jre子目录现在取消了bin目录里直接就是全套工具。1.2 版本选择策略LTS优先但要看清项目要求JDK的版本更新节奏是每半年一个大版本但只有LTSLong Term Support长期支持版本适合生产环境稳定使用。目前主流LTS版本是JDK 8、11、17和21。给个人学习和新项目选型我建议直接从17起步——模块化成熟、垃圾回收器性能好、Switch表达式和密封类这些新语法也都齐了IDE和主流框架的兼容性已经非常稳。但“最新”不等于“最适合你”。如果你是老项目维护比如公司里跑着基于JDK 8开发的Spring Boot应用或者那些对JDK版本敏感的老中间件老老实实用JDK 8。千万不要团队里别人用8你个人装个21代码里用了一堆新特性合并到分支直接编译不过。网上搜索记录里有个很典型的“jdk降级到17”说的就是装了21或更高版本后才发现某些第三方库不兼容只能卸了重装。我的建议是动手前先确认三件事——你手头项目的编译配置pom.xml或build.gradle里source/target版本、项目依赖的框架要求比如Spring Boot 3要求JDK 17Spring Boot 2要求JDK 8、以及团队统一的约定。先定版本再动手。1.3 JDK发行版怎么选Oracle JDK还是OpenJDK这是个老生常谈的问题。简单说Oracle JDK和OpenJDK在代码层面几乎没有差异从JDK 9开始Oracle JDK的构建过程也基于OpenJDK。Oracle JDK提供付费的商业支持适合企业买服务个人开发和学习用OpenJDK发行版完全够用不必纠结。目前国内开发圈用得较多的是这几类Oracle JDK官方版、Eclipse Adoptium原AdoptOpenJDK社区构建版、Amazon Corretto、Azul Zulu。我的私人偏好是Adoptium更新及时支持平台广安装包干净也可以直接下载tar.gz自己解压。给服务器装环境时常常用tar.gz方式不依赖系统的包管理器方便统一管理版本。下载渠道上Oracle JDK一定要去Oracle官网下载OpenJDK就去Adoptium官网下载。别在乱七八糟的第三方站点下“绿色版”“优化版”那个安全性无法保证而且JDK这种基础软件出问题排查起来非常浪费时间。2. 卸载旧JDK这一步做不干净后面全是坑2.1 Windows系统控制面板只是起点注册表和残留目录才是重头戏在Windows上卸载JDK大家都会先去“控制面板 → 程序 → 卸载程序”把Java相关的条目一个个卸掉。如果你只做到这一步就装新版JDK那只能算“表面干净”。实际工作中遇到的“java -version显示旧版本”“某个路径的java.exe一直删不掉”等问题十有八九都是残留导致的。完整卸载流程是这样的第一步先记下当前机器上Java的安装路径。怎么查在命令行里执行java -version看版本信息再执行where java能看到它找到的第一个java.exe在哪个目录。如果是通过安装包装的通常在C:\Program Files\Java\jdk-xxx。留意这个路径——稍后清理时要确认它还存不存在。第二步在控制面板卸载所有Java相关软件。包括JDK和独立的JRE条目。如果你装了多个版本建议全部卸掉再重新装一个目标版本省得后面“找不到jdk”或版本冲突。第三步删除残留目录。控制面板卸载完去C:\Program Files\Java看看正常情况下这个目录应该不存在或为空。如果里面还躺着jdk-8、jdk-17之类的文件夹直接删掉。还有C:\Program Files\Common Files\Oracle\Java\javapath这个目录里面放着java.exe、javaw.exe这几个关键可执行文件——它们优先级很高往往就是环境变量没配好但命令行依然能输出版本号、或输出版本号还是旧版本号的“元凶”。第四步清理环境变量。右键“此电脑 → 属性 → 高级系统设置 → 环境变量”在“系统变量”里找到JAVA_HOME如果指向上一步已删除的目录删掉或改为新路径。然后编辑Path变量把里面所有Java相关条目挑出来删掉常见的是C:\Program Files\Common Files\Oracle\Java\javapath和%JAVA_HOME%\bin。注意Path里可能还有其它软件写进去的Java路径逐条看清再删。第五步清理注册表。这是最容易被忽略的一步。WinR打开运行框输入regedit回车在注册表编辑器里定位到这三个位置HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft、HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\JavaSoft、HKEY_CURRENT_USER\SOFTWARE\JavaSoft。把它们整体删除。这三个键下记录着JavaSoft各产品JDK/JRE的安装路径和版本信息卸载程序经常会残留这些键值。不清掉的话后续用一些检测工具或者IDE自动探测JDK时可能还会识别到已经不存在的版本。注意修改注册表前建议先“文件 → 导出”备份一下万一删错还能恢复。注册表这东西删之前一定要看清路径层级。2.2 macOS系统目录删除加symlink检查macOS上卸载JDK相对简单。安装方式不同卸载路径也不同。如果是用官方.dmg安装包装的JDK默认装在/Library/Java/JavaVirtualMachines/目录下。把这个目录下对应的jdk-xxx.jdk文件夹整个拖到废纸篓并清倒基本就完成了。但还没完。需要检查/usr/bin/java这个符号链接指向哪里。在终端里执行/usr/bin/java -version如果还能显示版本说明系统里还有另一个JDK存在或者符号链接指向了已删除的路径。可以用ls -l /usr/bin/java查看它指向的路径如果指向的文件已不存在这个链接留着也无所谓Python或者系统脚本不会因为它出错。但如果它指向一个你不想要的旧版本JDK就需要用sudo rm -f /usr/bin/java删除后重新用ln -s建立指向新版本路径的链接。还有环境变量问题。macOS的Java环境变量配置位置和老Linux类似常见的是在~/.bash_profile或~/.zshrc里写了export JAVA_HOMExxx。卸载后这些旧export路径必须清理不然新开终端还是报“找不到JDK”。2.3 Linux系统包管理器卸载和手动解压两种方式Linux下JDK来源大体分两种通过apt/yum等包管理器安装的openjdk以及手动解压安装的tar.gz版本。如果是apt装的比如openjdk-11-jdk卸载命令是sudo apt remove openjdk-11-jdk想连配置文件一起清掉就加--purge参数。yum系的对应是sudo yum remove java-11-openjdk。包管理器卸载还算干净但也要注意/etc/profile或~/.bashrc里写入的JAVA_HOME和PATH行是否指向了已卸载的目录需要手动删掉。如果是手动解压的直接删除解压目录即可顺便清理软链接/usr/bin/java和/usr/bin/javac指向的目标以及环境变量配置。另外一定要执行hash -r或者重新登录会话清除shell的路径缓存。很多Linux用户报“明明删了目录执行java -version还能输出版本”就是这个缓存闹的。关于JAVA_HOME是否必须配置这里多说一句在Windows上JDK安装包有时会自动设置JAVA_HOME但不可靠在Linux/macOS上手动配置JAVA_HOME是标准做法。虽然不配也能直接用java命令但后续用Maven、Gradle、IDEA等工具时它们常常优先读取JAVA_HOME变量这个值不对工具就会报各种各样的错。3. 装新版JDK失败停不下来按这三步走3.1 安装前的路径规划装JDK不是双击下一步那么随意。我见过有人把JDK装到C:\Program Files\Java\jdk-17^1这种路径里结果后面写代码时路径里的特殊字符直接把脚本搞炸。选安装路径有三个原则不要包含中文、不要包含空格、不要用过于复杂的层级。Windows下建议直接装到C:\Java\jdk-17这种简洁目录或者保留默认的C:\Program Files\Java\jdk-17。如果机器C盘紧张也可以装到D盘但目录同样要遵循上面三个原则。macOS系统下直接用pkg安装包会装到/Library/Java/JavaVirtualMachines这个不用自己操心如果是用tar.gz手动解压建议放到~/java/jdk-17或者/usr/local/java/jdk-17这类路径。3.2 Windows安装包安装过程实操从官网下载的Windows安装包通常是.exe格式双击运行后进入图形化向导。有几个选项值得留意第一步安装程序会提示“选择要安装的功能”默认会安装“开发工具”“源代码”“公共JRE”——如果你只想装JDK公共JRE其实可以不勾选因为编译和运行Java程序都由JDK自带的bin目录解决。这个公共JRE不仅多余还会额外往注册表里写信息徒增卸载残留源。第二步是设置安装路径默认在C:\Program Files\Java\jdk-17.x.x。我建议改成C:\Java\jdk-17理由上面提过。如果你有强迫症也可以用默认路径后续能在IDE和脚本里正确引用即可。第三步等待安装完成。装完后下载下来的安装包文件可以留着做备份也可以删掉——个人选择。3.3 macOS和Linux的安装方式对比macOS用.pkg双击安装最省事自动完成JDK目录布局和符号链接工作。也可以通过Homebrew安装brew install openjdk17Homebrew会帮你安装到一个Cellar目录然后提示需要手动设置JAVA_HOME照着终端输出做就行。Linux服务器上我更推荐用tar.gz包解压的方式。原因有两个一是服务器一般没有桌面环境图形化安装程序没法跑二是tar.gz方式版本完全可控想装哪个版本就下载哪个版本解压后配一下环境变量即可。具体做法是# 下载jdk-17_linux-x64_bin.tar.gz后执行 sudo mkdir -p /usr/local/java sudo tar -zxvf jdk-17_linux-x64_bin.tar.gz -C /usr/local/java cd /usr/local/java sudo mv jdk-17.x.x jdk-17然后配置环境变量sudo vi /etc/profile # 文件末尾加上 export JAVA_HOME/usr/local/java/jdk-17 export PATH$JAVA_HOME/bin:$PATH保存退出后执行source /etc/profile让配置生效。然后验证java -version和javac -version都能输出版本信息就成功了。在Windows上装完JDK后环境变量不会自动配上尤其手工解压zip包的情况必须手动配这一步是用JDK过程中最容易出错的地方下一节单独说。4. 环境变量配置JDK装完真正的考验才开始4.1 JAVA_HOME、PATH、CLASSPATH各自负责什么先理解一下这三个变量的分工不然盲目照抄教程配错了都不知道怎么查。JAVA_HOME告诉系统和其它应用“JDK装在哪个目录”。Tomcat、Maven、IDEA这些工具都会读取这个变量。它的值是一个目录路径比如C:\Java\jdk-17不要带bin子目录也不要带引号。PATH系统在执行命令时按这个变量里的路径顺序查找可执行文件。要让java命令在任意目录下都能运行必须把%JAVA_HOME%\binLinux/macOS是$JAVA_HOME/bin加进Path变量。这样系统才能在bin里找到java.exe、javac.exe。CLASSPATH以前很多教程会配这个变量配成.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar。但在JDK 5之后的版本里CLASSPATH基本不再需要手动配置Java运行时会自动加载核心类库。配置错了反而容易出问题。新手教程里那句“必须配置CLASSPATH”早就过时了现在只配JAVA_HOME和PATH就够用。4.2 Windows图形界面配置实操在“系统变量”区点击“新建”变量名填JAVA_HOME变量值填你的JDK安装路径比如C:\Java\jdk-17这里要注意值是安装路径本身不要填到bin层。接下来在系统变量里找到Path双击进入编辑界面Windows 10/11会有一个列表式的编辑框点“新建”添加两行%JAVA_HOME%\bin这里还有一个常见的坑很多人会看到列表里已经有一条C:\Program Files\Common Files\Oracle\Java\javapath这是Oracle安装器写入的优先级高于%JAVA_HOME%\bin。如果两个地方对应的JDK版本不一致命令行里java -version显示的会是javapath指向的版本。所以要把它删掉只保留%JAVA_HOME%\bin即可。配置完成后关键一步是让环境变量生效。如果你是在IDE里装的插件或改了配置IDE内部可能要重启如果是命令行窗口必须关闭当前终端窗口重新打开一个新的CMD或PowerShell窗口。旧的终端窗口里保存的还是一份旧的环境变量快照直接执行java -version一定沿旧的来这基本是所有人配置完成后“没生效”的第一大原因。4.3 命令行验证和环境变量生效的判断方法新开一个CMD窗口输入下面三个命令做验证java -version javac -version echo %JAVA_HOME%第一和第二命令输出应显示你安装的目标版本第三命令打印的是你配置的路径。如果java -version输出了正确版本但echo %JAVA_HOME%输出空说明Path里可能是直接写的绝对路径而不是用%JAVA_HOME%引用的建议改成引用写法方便后续升级版本时只改一处。macOS和Linux下配置完环境变量后还需要注意一个细节——当前shell不会自动刷新profile文件的变量。常见做法是执行source ~/.zshrc或source /etc/profile来手动加载新配置。如果你发现source之后还是不行检查一下是不是在~/.bashrc、~/.zprofile、/etc/profile等多个文件里重复定义过JAVA_HOME后加载的会覆盖前面加载的这种情况常常导致“明明配好了又莫名失效”。4.4 用命令行临时指定JDK版本不想改全局配置的场景有时你不需要全局切换JDK版本只想在某个终端会话里临时用某个版本的JDK这个需求在服务器上很常见。做法是不修改系统环境变量而是在当前会话中临时exportexport JAVA_HOME/usr/local/java/jdk-17 export PATH$JAVA_HOME/bin:$PATH这个设置只对当前终端窗口生效关掉窗口就恢复原来的配置。Windows下同理临时在CMD窗口里执行set JAVA_HOMEC:\Java\jdk-17 set PATH%JAVA_HOME%\bin;%PATH%当前窗口临时用17其它窗口不受影响。这种“会话级切换”比动不动就改系统变量去折腾全局版本要安全得多。5. 装完老出问题常见报错和排查实录5.1 “找不到jdk” / “Unrecognized option” / “Could not find or load main class”先说“找不到jdk”。这个现象多见于Linux服务器准确说是系统里装了不同发行版的JDKjava命令能找到但JAVA_HOME变量没设置于是Shell脚本里用$JAVA_HOME/bin/java去执行时就会提示找不到jdk。排查方向很简单执行echo $JAVA_HOME如果输出空去/etc/profile和~/.bashrc里检查是否漏写了export语句。再说“Unrecognized option”这类报错。它长这样Unrecognized option: -version。这种大概率是shell的PATH里混入了非JDK的java。比如你在Windows上装了某些带有JRE的软件如Oracle客户端、部分开发工具自带OpenJRE它们会在Path里插一条自己带java的路径。你把系统环境变量配好也不行因为Path搜索顺序里前面的第三方路径先把java拦截了。处理方法执行where javaLinux下用which java看找到的java在哪个目录然后把真正的JDK路径调整到Path列表最前面或者删除第三方那条。最后是“Could not find or load main class”。这不是JDK安装的问题而是你用java命令跑.class或.jar时的一个经典报错。核心原因一般是类路径classpath没找到主类。排查步骤很固定先确认当前目录下.class文件存在再用java -cp . 你的类名这个方式显式指定当前目录为类路径这样能排除大部分CLASSPATH配置问题。5.2 环境变量配置失败可能是当前用户变量和系统变量打架配置环境变量时Windows里有两个容器用户变量和系统变量。注意最终生效的Path是两者拼接的结果系统变量在前用户变量在后。如果你之前在用户变量里配过一套JAVA_HOME或Java路径现在又在系统变量里配一套新的PATH里就会出现两个java路径。这种“双路径”状态是环境变量配置失败的常见隐藏原因。排查这个问题不要在“环境变量编辑框”里凭记忆看最好的方式是打开命令行直接执行echo %PATH%把输出的内容里所有Java相关条目列出来看有没有重复指向不同版本的情况。然后回到图形界面把用户变量和系统变量里多余的那条删掉只保留一套。路径拼接顺序导致的另一个问题是如果你在用户变量里指向的是旧JDK系统变量里指向新JDK命令行执行java -version显示的还是旧版本因为Path搜索是从前往后的。所以配置完成后用where java确认一下实际命中的路径再判断要不要调整优先级。5.3 Win11下装老版本JDK比如JDK 1.6遇到的问题搜索记录里有个很有意思的词win11 jdk 1.6环境设置。这其实是个相对极端的情况。JDK 1.6即Java 6是2006年发布的老古董设计时根本没考虑过Windows 11会存在。它在Win11上常见的两个问题是安装时提示“此应用无法在你的电脑上运行”以及环境变量配好了还是一堆乱码报错。如果是老项目实在绕不开JDK 6我的建议是不要直接裸装在Win11上而是想办法通过Docker容器跑老版本JDK或者用虚拟机装老系统跑。原因很现实JDK 6年代的安全协议、TLS版本都太老连现代的Git仓库都连不上而且与新硬件的兼容性没保证。如果你只是学习环境下测试某个老项目装个JDK 8基本就够用了它是最后一代支持32位系统和大量老库的版本也是在Win11上还能稳定运行的JDK系列里“最老”的合格候选人。5.4 搜“bcprov-jdk”时选对版本比硬凑重要热搜词里有“jdk 17 增加bcprov-jdk 选择什么版本”这是个典型的依赖协调问题。bcprov-jdkBouncy Castle加密库的构件名里有些带“jdk15on”“jdk18on”字样这里的“on”后缀并非指JDK 15或18而是指该版本是用某个Java版本编译的基线。jcajce版本的兼容范围通常是向后的只要不低于依赖你的项目的JDK版本就能跑。如果你用的是JDK 17选择bcprov-jdk18on-1.xx注意是18on不是15on就正好合适它能完整支持17的新加密API。如果项目里已经锁定了老版本bcprov-jdk15on在JDK 17出问题时往往不是库本身的问题而是它在运行时反射访问内部API时被模块系统拦住了。处理方式是项目里加上适当的JVM参数最省事的还是换18on版本。这种问题要想一次到位原则很简单打开项目的pom.xml或build.gradle看依赖管理里bcprov-jdk的groupId和artifactId然后去中央仓库Maven Central找该项目最新版本比对它的编译基线和你项目的JDK版本选不低于JDK版本的即可。5.5 IDE配置JDK不生效常见原因和处理在IDEA里改完Project Structure里的SDK路径但代码里import的类还是报红这属于“IDE配置JDK不生效”。多数情况是三个层面没对齐Project SDK、Java Compiler的target bytecode version、以及Maven/Gradle使用的JDK。IDEA的Project Structure里Project SDK选到目标JDK之后还要看Settings → Build Tools → Maven → Importing里的JDK版本。Maven项目编译时如果这里指定了一个不同的JDKIDEA右下角跑出来的编译错误就会很奇怪。Gradle项目还有一个核心问题Gradle本身运行所需的JVM和编译项目的JDK可以是两个东西如果你在Gradle配置里用了toolchain它甚至可能绕过你机器上的JDK自动去下载一个它认为合适的JDK。处理办法说来也不复杂确认三处版本一致——Project SDK、编译器字节码版本比如17对应Java 17、构建工具运行用JDK。如果有条件用一个相对干净、独立的JDK目录不要在IDEA的“Add SDK”里选那种带括号的临时下载包免得目录被自动删除后工程全部报红。6. 那些和“JDK”有关联的工具和原理顺带说清楚6.1 Maven、JMeter、IDEA这些工具为什么都绕不开JDK环境搜索记录里还有“jdk maven navicat”“jmeter安装教程以及jdk环境配置”这类词说明不少人是在装完JDK后要为其它工具铺路。这里补充说明一下JDK在这些工具里扮演的角色。Maven是Java项目的构建工具它本身是用Java写的运行时就必须依赖JDK环境。你执行mvn命令本质上是JVM在跑Maven程序。它读pom.xml后调用javac编译项目代码。所以JAVA_HOME配置不对Maven可能能启动但编译时提示“Unable to locate the Javac Compiler”或“No compiler is provided in this environment”。JMeter是接口性能压测工具同样是个Java程序启动脚本jmeter.bat里会去找JAVA_HOME。它比Maven更挑剔如果你装了太新的JDK比如25JMeter某些插件和JVM参数可能不兼容如果你用旧JMeter版本配合JDK 17反而比JDK 21或者更高版本顺手。一般建议兼顾稳定性的做法是JMeter 5.x搭配JDK 8或11。装完JMeter后解压即用核心就是验证java -version正常然后双击jmeter.bat启动GUI。NAVICAT这个数据库客户端虽然是收费软件但历史版本有些功能依赖Java运行时如果它自带的JRE版本偏老就可能和新装的JDK冲突。处理方式通常是装回它自带的JRE版本或者给启动脚本指定JAVA_HOME。6.2 AOP实现原理里的JDK动态代理与CGLIB看到“aop实现原理-jdk动态代理”这个词我想很多写Spring的读者也在疑惑Spring AOP的底层到底做了什么。这里用几句话把关键机理讲清楚。Spring AOP在运行时给目标bean生成代理对象有两种方式。优先使用JDK动态代理前提是目标对象实现了至少一个接口。JDK动态代理用的是java.lang.reflect.Proxy类它基于接口生成一个代理类这个代理类实现了同样的接口并且在调用方法时转发给InvocationHandler的invoke方法你在invoke里写前置、后置、环绕逻辑。整个过程是在运行时动态生成的不需要修改字节码文件核心是Java反射。如果目标对象压根没实现任何接口JDK动态代理就没法用了。Spring会退而求其次使用CGLIB生成目标类的子类通过覆盖目标方法并织入通知逻辑来实现代理。CGLIB走的字节码增强路线它生成的是目标类的子类对象所以要求目标类不能被final修饰否则没法被继承。搞懂这两者的区别很多Spring AOP“方法内部调用不生效”的经典问题就容易理解了同一个类里的方法调用走的是this调用绕过了代理对象所以Transactional和Async这类基于代理的注解不生效。这也是为什么面试题里总爱问“JDK代理和CGLIB的区别”。6.3 JDK源码要不要下载、怎么读有的热搜词是“jdk源码视频”这里顺带说点实在的。JDK安装包里通常带有源码压缩包src.zip在安装目录下能找到。把它解压到IDE里源码阅读体验会好很多。读源码建议从这几个包开始java.langString、Object、Integer、java.utilHashMap、ArrayList、ConcurrentHashMap、java.ioInputStream、File、java.nioBuffer、Channel、java.util.concurrent线程池、锁。初学者不建议一上来就啃并发包容易迷路。建议从HashMap的Java 8实现开始——它从数组加链表演进到红黑树的阈值逻辑、扩容退化的机制几乎一篇源码解析视频就能把集合类核心知识点串起来。把源码关联配好之后在IDEA里按住Ctrl点类名就能跳转进源码这对排查“这个方法到底怎么走的”非常有用。我个人在实际操作中的体会是JDK的环境问题80%出在卸载残留和环境变量优先级20%才是安装本身失败。所以这篇文章里卸载和环境变量两块写得最多。如果你只是照着教程一路下一步装好了、跑通了那挺幸运但如果哪天遇到怪问题建议回到这里用“卸干净 → 选对版本 → 配单一环境变量 → 新开终端验证”这套流程重新推一遍。另外再分享一个小习惯JDK装好后第一件事不是急着写Hello World而是先建一个txt记下JDK安装路径、版本号和配置时间。下次换版本、排查问题这份记录能直接节省半小时。