(这里记录了笔者了解的关于JDK环境配置的信息,以及针对系统上存在不同版本JDK时所尝试的解决方案。具体来说,是已安装 JDK 8 后,又安装了 JDK 9 时所遇到的问题和尝试的解决方法。这次记录以供有同样问题的人士参考,也希望能给遇到类似问题的人士提供启发和思路。)
笔者最近在PC上安装了Qt Creator,并按要求为其配置了所需的java 9.0.4环境,结果便发现之前安装好的软件包括eclipse、JEB2 等依赖Java运行时环境的软件出现了无法使用的问题,eclipse直接无法打开,而JEB2打开软件后大部分功能按键无法使用。经过排查和搜索资料后认定这是由于安装两个不同版本的JDK后无法满足上述不同软件的运行环境需求所产生的问题。
名词解释(摘自Wiki)
JDK:Java Development Kit,Java程序开发组件,是针对Java的免费软件开发工具包( SDK,software Development Kit ),为Java程序的开发提供支持,也目前是最受欢迎的 Java SDK;
JRE:Java Runtime Environment,Java运行时环境,包含java虚拟机和若干标准函数库,为Java程序在系统上运行提供支持;
Windows环境下的JDK Installer会包含JDK和JRE的安装选项。一般情况下,会默认安装上述两个Java组件。当然,若用户只需要提供对 Java 运行时环境的支持,则只需要安装 JRE 以节省系统资源。
回顾——如何配置Java环境
这里为了能够更好的完成不同版本JDK的配置问题,首先回顾一下第一次为设备设置Java环境时进行的操作( 以JDK 8为例)。
(1)我们通过 JDK Installer ,选择了我们需要的组件,一般情况下会选择默认的设置,也就是 JDK、JRE和公共JRE,并将他们安装在默认的安装路径上,在笔者例子中,是 C:\Program Files\Java\jdk1.8.0_92 目录;
(2)我们需要为Java环境设置环境变量,在 开始-> 系统 -> 左侧高级系统设置 -> 环境变量 ( 以Win8.1为例 )中设置了若干环境变量
a) JAVA_HOME :新建一个名为JAVA_HOME的系统变量,存放的是JDK所在的安装目录;
b) CLASSPATH :新建一个名为 CLASSPATH的系统变量,存放的是可用于寻找Java库的目录;
c) Path:在Path变量中,添加了路径 %JAVA_HOME%\bin 和 %JAVA_HOME%\jre\bin ,这两项使用JAVA_HOME变量合成了更复杂的路径,也就是相当于 将C:\Program Files\Java\jdk1.8.0_92目录下的\bin目录和 \jre\bin目录加入了Path变量,这些bin目录中存放了Java开发(\bin)和运行(\jre\bin)相关的可执行文件;
JAVA_HOME C:\Program Files\Java\jdk1.8.0_92
CLASSPATH .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar
Path %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin
(注:有资料中表述,Win10环境下,只能为Path添加绝对路径,不能使用JAVA_HOME变量来合成路径)
这里介绍一下Path变量的作用:Path变量中记录了一系列的文件目录路径,当在命令行中执行命令时,如在 cmd 中键入 java 时,系统首先在当前目录下寻找对应名称的文件,找不到对应的文件时,则会以Path变量中记录的路径顺序,依次去检索这些目录下的文件,直到寻找到与命令名相同的目标文件(一般是可执行文件.exe,如 java.exe),之后系统将命令行参数传递给找到的目标文件并执行之,从而实现命令的执行。实际上,许多图形化界面下的操作最终都换转化为命令行的方式执行。这也就是需要配置Java环境的原因,简单的说就是使得系统知道哪里可以找到Java开发(如Java编译器)和运行(Java虚拟机)所需要的可执行文件。若没有指定Path路径,则需要通过指定完整的路径名来执行文件,如
> "C:\Program Files\Java\jdk1.8.0\bin\javac" -version //没有添加路径至Path变量时,需要给出完整的路径才能执行,且路径中若包含空格需要用""包含路径名
> javac -version //添加路径 C:\Program Files\Java\jdk1.8.0\bin\ 至Path变量后(同样也需要用""包含带空格的路径),可以直接输入命令,系统会根据Path找到目标文件
完成上述设置后,每当 java 相关的任务需要执行时,系统就会在 Path 路径中进行查找(若当前目录中找不到的话),并由查找到的exe程序执行所要求的任务。
当安装一个新版本的 JDK 时,安装程序会安装必要的文件,但不会修改上述这些变量的值,故而这些环境变量值是需要重新手动配置的。
查看当前系统的Java配置
Windows环境下,若 java 环境安装和配置成功完成,则可通过cmd运行得到系统上的 java 环境相关参数。
(1)通过 javac -version 获得java编译器的版本(等同于 jdk 版本,开发需要)
(2)通过 java -version 获得java虚拟机等相关的版本信息( 等同于 jre版本 ,运行需要)
命令行的运行方式在之前已经给过介绍,系统首先在当前目录下查找,若找不到,则根据环境变量 Path 中设置的众多目录按顺序进行查找,直到在某一文件中查找到 javac.exe 文件,则将参数 -version传递给该程序,并继续执行,该程序则会将执行结果输出。
从图示可以看到,笔者PC上由于安装了两个不同版本的JDK,且在较新版本的JDK安装后并没有正确的配置环境,使得系统在执行上述 javac 和 java 命令时,分别在两个不同的文件夹中找到了两个不同版本的可执行文件。这样(不统一)的JDK环境是可能造成错误的。
关于公共JRE( public jre )
在Oracle的文档中( jdk 8 )找到的关于公共jre的描述:
Private Versus Public JRE
Installing the JDK also installs a private JRE and optionally a public copy. The private JRE is required to run the tools included with the JDK. It has no registry settings and is contained entirely in a
jre
directory (typically atC:\Program Files\jdk1.8.0\jre
) whose location is known only to the JDK. On the other hand, the public JRE can be used by other Java applications, is contained outside the JDK (typically atC:\Program Files\Java\jre1.8.0
), is registered with the Windows registry (atHKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft
), can be removed using Add/Remove Programs, might be registered with browsers, and might have thejava.exe
file copied to the Windows system directory (which would make it the default system Java platform)
JDK 8 在安装JDK时,会在JDK安装目录下安装其私有JRE,该JRE仅用于对JDK的工具提供支持,该JRE没有注册表项,只作为JDK安装目录下的/jre目录存在,即不用做为外部应用提供支持。用户可以选择是否安装 public jre ,其为其他的java应用提供运行支持,一般被安装在一个单独的目录下,会有注册表项,同时其中的java.exe文件可能会被复制到Windows的系统目录下( 如 C:\Windows\System32 目录下 )。当然,更简单的一种做法即为不安装额外的 public jre,而是直接将 JDK 安装目录下的 JRE 用作公共 JRE,即将其路径加入Path中,这也是之前介绍的配置的做法( 因为公共 JRE 本身就是私有 JRE 的一个拷贝,但是其是有注册表项的)。
JDK 9 中,安装64-bit JDK时会默认安装公共JRE(也可以取消默认安装)。同时 JDK 9 中的目录结构发生了变化(见下)。
When you install 64-bit JDK, then 64-bit public JRE also gets installed
不同版本之间Java环境的差异
由于上述通过cmd获得Java版本序列号之间存在较大差异,笔者猜测两个版本之间可能存在较大的变动,所以笔者在JDK 9 Migration Guide 中查看了 JDK 9 与之前版本的变化情况的描述。
其中与目前笔者所使用JDK相关的差异信息( JDK 8 与 JDK 9 )如下:
(1) 使用了新的版本字符串格式:JDK 9使用的是 $MAJOR.$MINOR.$SECURITY.$PATH 的版本表示格式(如上图 java 9.0.4 ),JDK 8中,JDK为 1.8,而JRE为1.8.0,JRE 8 update 92( JDK 8u92 ) 即为 JRE 1.8.0_92;
(2) JDK 9的目录结构较之前面版本出现了变化,在JDK 9 之前的版本中,私有JRE是包含在JDK安装目录下的 /jre目录下的,而JDK 9中,私有JRE不再通过单独的/jre文件夹存放,而是直接分散在JDK目录下。在安装JDK 8时,我们在 Path 环境变量中分别加入了 jdk 和 jre 文件夹下的 /bin 文件夹路径,在JDK 9 环境下这两个路径就会有所不同;
(3) JDK 9版本之前,系统提供的类存放在 /lib/rt.jar 和 /lib/tools.jar文件中,而在 JDK 9版本中,上述两个文件连同 /lib 文件夹下的一些其他的内部的jar文件以一种更高效的方式组织在一起,存放在 /lib 文件夹下。也就是说,上述两个文件已经不存在了。回忆一下,我们在安装JDK 8设置 CLASSPATH 时加入了这两个文件的路径;
(4) 注册表中的表项发生了变化,在JDK 8中,安装JRE后,会出现如下的注册表项
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\1.8
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\1.8.0_144
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment@CurrentVersion=1.8
//当JDK也被安装时,添加的注册表项为上述表项中 Java Runtime Environment 字段被 Java Development Kit 替换后的结果
而在JDK 9中,安装JRE后,出现的注册表项如下
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\JRE
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\JRE\
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\JRE@CurrentVersion=
//当JDK也被安装时,添加的注册表项为上述表项中 JRE 字段被 JDK 替换后的结果
由于上述两组注册表项并不同名,故而若同时安装了这两种 JDK 环境,则会同时出现上述两种注册表项,
针对不同JDK版本的解决方法
1.一个临时的解决方法:删除新版本的JDK
通过Windows自带的卸载程序可以卸载新安装的JDK,在 开始-> 控制面板 -> 程序 -> 卸载程序 (Win8.1为例),卸载新安装的 JDK ( 包括公共JRE等 ),则系统会恢复至单 JDK 版本的状态,故而原设备上安装的软件应该就可以正常运行了,但该方法只能解一时之急,当出现需要依赖新版本的 JDK 的应用时,还是需要安装新版本的 JDK 以供使用。
2.安装 JDK 9 ,但选择不安装公共 JRE 时
此时系统中会存在两个 JDK 目录(安装新版本的 JDK 并不会删除旧版本的 JDK ),根据之前的介绍,配置合适的 JDK 环境简单的来讲就是使得对应的程序能够寻找到所需的可执行文件( 通过 Path 路径 ),故而这里需要的即为配置 Path 路径。由于之前配置 JDK 8 时已经设置好了一部分,故而只需要对其进行修改即可。
JAVA_8 "C:\Program Files\Java\jdk1.8.0_92\bin" //新建一个系统变量,存放 JDK 8的安装路径
JAVA_9 "C:\Program Files\Java\jdk-9.0.4\bin" //新建一个系统变量,存放 JDK 9的安装路径
JAVA_HOME %JAVA_9% //需要某一个JDK版本,则将% %中的变量修改为对应的值即可
上述修改在重新打开命令行后即可生效,可以通过 java -version 和 javac -version 查看对应的版本是否已经切换。事实上,这里与应用程序启动和运行相关的是 JRE 而不是 JDK(见定义),而在 JDK 8 中,私有 JRE 就存放在 JDK 的安装目录下的,指定了 JDK 目录后,Path 路径中已存在 %JAVA_HOME%\jre\bin 条目,即指明了私有 JRE 路径,从而应用程序可在运行时通过 Path 可以找到该 JRE。而 JDK 9 中,如上所述,已经将私有 JRE 整合在了 JDK 目录中,故而只需指定对应的 JDK 的可执行目录,也就是之前已经编辑了的 %JAVA_HOME%\bin 条目,即可获得对应的 JRE 环境。
这样,在需要特定的 JDK/JRE 环境时,只需要将 JAVA_HOME 变量的值修改为对应版本的 JAVA_n 即可。
3.安装 JDK 9 , 但选择安装公共 JRE 时
选择安装公共 JRE 时,则会在新安装的 JDK 目录之外多出一个新的 JRE 目录,该目录中含有可为应用程序提供运行支持的 JRE 相关的可执行文件。从之前的介绍可以看出,该 JRE 就是一个私有 JRE 的副本,但是其是由注册表项的。这种情况下使用 java -version 和 javac -version 的结果就是笔者设备之前截图的情况。此时想要获得不同版本的 JDK 的支持,一方面,对于 JDK 的支持,则需要依据实际情况修改 JDK 的 Path 路径,使其指向不同的 JDK 安装目录;而对于 JRE 的支持,由于公共 JRE 是有注册表项的,故而除了需要修改系统变量 Path 中的路径外,可能还需要修改对应的注册表项。总的来说,这种方法不是很推荐,因为不安装公共 JRE 时的配置更简单,且可以满足同样的需求。
4.针对特定的程序的 JDK 配置
正如之前强调的,安装新版本的 JDK 时,并不会删除旧版本的 JDK 文件。更新某个新版本的 JDK ,并将环境变量修改为指向新版本的 JDK 路径后,即完成了新版本 JDK 的安装,对于 Java 运行环境有特定需求的应用程序所需要的是 JRE 的支持,当特定应用程序运行时,应用会根据新设置的路径找到新版本的 JDK 提供的 JRE ,从而出现环境不匹配的问题,而实际上,只要不卸载旧版 JDK ,应用运行所需的 JRE 环境是可以在系统中找到的,故而只需修改特定程序的配置,使其直接使用旧版本的 JRE 即可(而不是根据Path路径去寻找JRE)。
如对于eclipse,可编辑其安装目录中的 eclipse.ini 文件,在其开始处增加内容 -vm 旧版本JRE的bin目录路径 即可。在笔者设备中,即在文件头部增加以下内容:
-vm
C:\Program Files\Java\jdk1..0_92\jre\bin
即可使得程序能正确找到运行所需要的 JRE 环境,从而能够成功启动。