JavaSE-07-1

偷一波自己的图 :)

JDK(Java Development Kit):Java程序开发工具包,包含JRE和开发人员使用的工具。其中的开发工具有编译工具 (javac.exe)和运行工具(java.exe)。如果想开发一个全新的Java程序,必须安装JDK。

JRE(Java Runtime Environment):Java程序运行时的环境,包含JVM和运行时所需的核心类库。若想运行一个已有的Java程序,只需要安装JRE即可。

JVM( java virtual machine):Java虚拟机,JRE的一部分,是一个虚构出来的计算机,支持跨平台。

翻一下Java的默认安装路径,可以看到有两个JRE文件夹,路径分别为:C:\Program Files\Java\jdk1.8.0_151\jreC:\Program Files\Java\jre1.8.0_151 。而且细看之下,文件夹里的内容基本一样。这让人很疑惑为什么会有两套JRE?

这里先将C:\Program Files\Java\jdk1.8.0_151\jre\lib的tools.jar改个名字(完了记得改回来),然后用javac命令编译一个源文件:

JavaSE-07-2

从中我们可以推测,javac.exe本质上是要经过lib目录下的tools.jar中的com.sun.tools.javac.Main执行,所以javac.exe只是一个包装器 (Wrapper),存在的目的是为了让开发者免于输入过长的指命。

这个时候发现JDK里的工具几乎是用Java所编写,同属于Java应用程序,因此要使用JDK里的工具来开发Java程序,自身需要附一套JRE才能运行。所以上面提到的两个路径下的JRE都可以作为开发时Java程序的运行环境,但是JDK自带的工具只能使用C:\Program Files\Java\jdk1.8.0_151\jre目录下的JRE。

那么在运行一般的Java程序时由谁来判断使用哪一个JRE呢?在命令提示符中,使用 java 文件名 命令来执行字节码文件时,由java.exe来进行判断,并使用以下顺序:

  1. 首先会检查当前工作目录(即执行java命令时所处的目录)中是否存在JRE
  2. 如果在当前工作目录下没有找到JRE,则java.exe会继续检查当前工作目录的父级目录(上一级目录),看是否存在JRE
  3. 如果在当前工作目录及其父级目录下都没有找到JRE,java.exe会进一步查找Windows系统的注册表,特别在HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment路径下查找已安装的JRE信息

一旦找到了符合条件的JRE,java.exe就会停止继续搜索,并使用找到的JRE来执行Java程序。这也解释了为什么JDK自带的工具只能使用JDK自带的JRE。

再说JVM,所有的Java源文件会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行,.class文件并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行,类似于C#中的CLR。JVM不能单独搞定class的执行,解释class的时候JVM需要调用解释所需要的类库lib。在JDK下面的的jre目录里面有两个文件夹bin和lib:

JavaSE-07-3

在这里可以认为bin里的就是JVM,lib中则是JVM工作所需要的类库,而JVM和 类库合起来就称为JRE。如果讲得具体点就是bin目录下的jvm.dll文件, jvm.dll无法单独工作,当jvm.dll启动后,会使用explicit的方法(就是使用Win32 API之中的LoadLibrary()与GetProcAddress()来载入辅助用的动态链接库),而这些辅助用的动态链接库(.dll)都必须位于jvm.dll所在目录的父目录之中。因此想使用哪个JVM,只需要设置Path来指向JRE所在目录下的jvm.dll。