1.4 Java的魔力:字节码
允许Java解决刚才描述的安全性和可移植性问题的关键是,Java编译器的输出不是可执行代码,而是字节码(bytecode)。字节码是高度优化的指令集合,这些指令由Java运行时系统执行,Java运行时系统也称为Java虚拟机(Java Virtual Machine,JVM)。本质上,原始的JVM被设计为字节码解释器(interpreter for bytecode)。这可能有点让人吃惊,因为出于性能方面的考虑,许多现代语言被设计为将源代码编译成可执行代码。然而,Java程序是由JVM执行的这一事实,有助于解决与基于Web的程序相关的主要问题。下面分析其中的原因。 将Java程序翻译成字节码,可以使其更容易地在广大范围的可变环境中运行,因为只需要针对每种平台实现Java虚拟机就可以了。对于给定的系统只要存在运行时包,所有Java程序就可以在该系统上运行。请记住,尽管对于不同的平台,Java虚拟机的细节可能有所不同,但是它们都能理解相同的Java字节码。如果Java程序被编译成本机代码,就必须为相同的程序针对连接到Internet的不同类型的CPU提供不同版本。因此,通过JVM执行字节码是创建真正可移植程序最容易的方法。 Java程序由JVM执行的这一事实,还有助于提供安全性。因为JVM是可控的,所以能够包含程序并防止它在系统之外产生负效应。在后面将会看到,安全性也是通过Java语言具有的特定限制得到增强的。 一般而言,如果将程序编译成中间形式,然后由虚拟机解释执行,相对于直接编译成可执行代码,执行速度要慢一些。然而对于Java而言,这两种方式之间的区别不是特别大。因为字节码已经被高度优化,使用字节码能够使JVM执行程序的速度,比您可能认为的速度快得多。
尽管Java被设计成一种解释语言,但是为了提高性能,完全可以将字节码编译为本机代码。为此,在Java最初发布不久就引入了HotSpot技术。HotSpot为字节码提供了即时(Just-In-Time,JIT)编译器。如果JVM包含JIT编译器,就可以根据要求一部分一部分地将选择的字节码实时编译为可执行代码。不是将整个Java程序一次性地全部编译为可执行代码,理解这一点很重要,因为Java执行各种运行时检查,而这些检查只有在运行时才执行。事实是,JIT编译器在执行期间根据需要编译代码。此外,不是编译所有字节码序列——而是只编译那些能从编译中受益的字节码,剩余代码仍然只是进行解释。尽管如此,这种即时编译方法仍然可以显著提高性能。当对字节码应用动态编译时,仍然可以获得可移植性和安全性,因为JVM仍然控制着执行环境。