1.6 Java跨平台的原理

在了解了Java的一些特性之后,我们知道Java是平台无关的,那么Java是怎么做到跨平台的呢?这一切的“魔法”源于JVM(Java Virtual Machine,Java虚拟机)。

1.6.1 Java源文件的编译过程

Java应用程序的开发周期包括编译、下载、解释和执行几个部分。Java编译器将Java源程序翻译为JVM可执行的代码——字节码。这一编译过程与C/C++的编译有些不同,C/C++编译器生成的代码是针对某一硬件平台的代码。因此,在编译过程中,编译器通过查表将所有对符号的引用转换为特定的内存偏移量,以保证程序的正确运行。而Java编译器则不会把对变量和方法的引用编译为数值引用,也不确定程序运行过程中的内存布局,而是将这些符号引用信息保留在字节码中,由解释器在运行时去创建内存布局,然后再通过查表来确定一个方法所在的地址,这样就有效地保证了Java的可移植性和安全性。

1.6.2 Java解释器运行机制

运行字节码的工作是由解释器来完成的。解释执行过程分为三步:代码装入、代码校验、代码执行。

代码装入的工作由类加载器(Class Loader)来完成。类加载器负责加载运行程序所需要的所有代码。当类加载器加载一个类之后,类被放在自己的名字空间中,除了通过符号引用自己名字空间以外的类,类与类之间没有其他办法可以相互影响。当加载了运行程序所需要的所有类之后,解释器便可以确定整个可执行程序的内存布局,并为符号引用同特定地址空间建立对应关系查询表。通过在这一阶段确定代码的内存布局,Java很好地解决了由于基类改变而导致子类崩溃的问题,同时也防止了代码对地址的非法访问。

当代码被装入之后,字节码校验器开始对字节码进行检查。校验器可以发现操作数栈的溢出和非法数据类型转换等多种错误。在校验通过后,Java代码便开始执行了。

1.6.3 Java字节码的执行方式

Java在执行字节码时有两种方式:即时编译方式和解释执行方式。即时编译方式(JIT Just In Time)先将字节码编译成机器码,再执行机器码。这种运行方式的优点是执行经过二次编译后的机器码可以提高程序的执行速度。

解释执行方式是解释器通过每次解释,并执行一小段代码来完成Java字节码程序的所有操作。比如,若Java字节码要对两个数值进行加法操作,则解释器调用自身的一段代码来完成加法操作。

1.6.4 理解JVM

前面提到了JVM、解释器、编译器、字节码等概念,那么它们之间的关系是怎样的呢?让我们来举个例子说明一下。

我们把Java源程序想象为C++源程序,那么Java编译器生成的字节码就相当于C++编译器编译的针对Intel x86平台的机器码(二进制程序文件)。由于字节码是通过JVM来运行的,所以JVM可以被看成一台配备Intel CPU的计算机。Java解释器是JVM中的一部分,它是用来实际执行Java字节码的,所以解释器更像是Intel CPU。JVM与Java解释器和字节码的关系如图1-6所示。

img

图1-6 JVM与解释器

Java解释器相当于运行Java字节码的“CPU”,而这个CPU不是由硬件实现的,而是由软件实现的。Java解释器实际上是一个针对不同硬件平台设计的一个软件。只要实现了特定平台下的Java解释器,Java字节码就可以通过解释器在该平台下执行。这就是Java跨平台的根本。

img

图1-7 Java跨平台原理

不过,并不是在所有的平台下都有Java解释器,也就是说Java程序并不能在所有的平台下运行,Java程序只能在实现了Java解释器程序的平台下运行。