1.3 Java程序的生命周期
为了更好地理解 Java 代码是怎么编译和执行的,以及 Java 和其他编程环境的区别,请看图 1-1 中的流程图。

图 1-1:Java 代码是怎么编译和加载的
整个流程从 Java 源码开始,经过 javac 程序处理后得到类文件,这个文件中保存的是编译源码后得到的 Java 字节码。类文件是 Java 平台能处理的最小功能单位,也是把新代码传给运行中程序的唯一方式。
新的类文件通过类加载机制载入虚拟机(有关类加载机制更详细的说明参见第 10 章),从而把新类型提供给解释器执行。
常见问题解答
本节解答一些关于 Java 和在 Java 环境中编写的程序的生命周期的最常见问题。
1. 字节码是什么
开发者首次接触 JVM 时,可能认为它是“电脑中的电脑”,然后顺其自然把字节码理解为“内部电脑中 CPU 执行的机器码”或“虚拟处理器执行的机器码”。
其实,字节码和运行于硬件处理器中的机器码不太一样。计算机科学家视字节码为一种“中间表现形式”,处在源码和机器码之间。
字节码的目的是,提供一种能让 JVM 解释器高效执行的格式。
2. javac是编译器吗
编译器一般生成机器码,而 javac 生成的是和机器码不太一样的字节码。不过,类文件有点像对象文件(例如 Windows 中的 .dll 文件,或 Unix 中的 .so 文件),人类肯定读不懂。
在计算机科学理论的术语中,javac 非常像编译器的“前半部分”,它生成的中间表现形式可以进一步处理,生成机器码。
不过,因为类文件的生成是构建过程中单独的一步,类似于 C/C++ 中的编译,所以很多开发者都把运行 javac 的操作称为编译。在本书里,我们使用术语“源码编译器”或“javac 编译器”表示生成类文件的 javac。
我们把“编译”看作一个单独的术语,表示 JIT 编译,因为只有 JIT 编译才会生成机器码。
3. 为什么叫“字节码”
指令码(操作码)只占一个字节(有些操作还可以有参数,即跟随其后的字节流),所以只有 256 个可用的指令。实际上,有些指令用不到,大概只会使用 200 个,而且其中还有一些是最新版 javac 不支持的。
4. 字节码是优化过的吗
Java 平台的早期阶段,javac 会对生成的字节码进行大量优化。后来表明这么做是错的。JIT 编译出现后,重要的方法会被编译成运行速度很快的机器码。之所以要减轻 JIT 编译器的负担,是因为 JIT 编译获得的效果,比字节码优化多很多,而且字节码还要经过解释器处理。
5. 字节码真的与设备无关吗?那字节顺序呢
不管在哪种设备中生成,字节码的格式都是一样的,其中也包括设备使用的字节顺序。如果你想知道,我告诉你,字节码始终使用大字节序(big-endian)。
6. Java是解释性语言吗
JVM 基本上算是解释器(通过 JIT 编译大幅提升性能)。可是,大多数解释性语言(例如 PHP、Perl、Ruby 和 Python)都直接从源码解释程序(一般会从输入的源码文件中构建一个抽象句法树)。而 JVM 解释器需要的是类文件,因此当然需要多一步操作,即使用 javac 编译源码。
7. 其他语言可以在JVM中运行吗
可以。JVM 可以运行任何有效的类文件,因此,Java 之外的语言可以通过两种方式在 JVM 中运行。第一种,提供用于生成类文件的源码编译器(类似于 javac),以类似 Java 代码的方式在 JVM 中运行(Scala 等语言采用的是这种方式)。
Java 之外的语言可以使用 Java 实现解释器和运行时,然后解释该语言使用的源码格式。JRuby 等语言采用的就是这种方式(不过 JRuby 的运行时很复杂,某些情况下能辅助 JIT 编译)。
