大多数开发人员都知道,Java源文件需要编译成.class文件才能在JVM中运行。如果继续追问,许多开发人员还会告诉你说.class中的字节码首先会被JVM解释,但是在稍后即时(JIT)编译。然而很多人将字节码含糊地理解为“在某种虚构的或者简化的CPU上运行的机器码”。

实际上,JVM字节码更像是中途的驿站,是一种从人类可读的源码向机器码过度的中间状态。用编译原理术语讲,字节码实际上是一种中间语言(IL)形态,不是真正的机器码。也就是说,将Java源码变成变成字节码的过程不是C或C++程序员所理解的那种编译。Java所谓的编译器javac也不同于gcc,实际上它只是一种针对java源码生成类文件的工具。Java体系中真正的编译器是JIT:

1
2
3
4
5
javac 类加载器
.java ----------> .class ------------>
解释器 JIT编译器
转换后的.class ---------> 可执行代码 ------------> 101011机器码

有人说Java是“动态编译”的,他们说的编译是指JIT的运行时编译,不是指构建时创建类文件的过程。

所以如果被问及“Java是编译型语言还是解释型语言”,你可以回答“都是”。


2015年2月5日

昨天和同事突然又讨论到这个问题,然后又想了一下这个问题。

有很多人倾向于避开将语言按照解释型和编译型还区分,应该区分得更细化一点了,强类型的、弱类型的,静态的、动态的,GC-based的、手工管理内存的,有没有VM…

从某个科学的角度(书读得少,不知道怎么描述这个角度= =)来说,编译型和解释型可以说相同,因为都是从文本形式的代码转换到最终的相同目的。

一段来自知乎的文字:

现在关于解释和编译的界限也不是特别清晰了。

  • Java需要预先把代码编译成虚拟机指令的,然后在运行这些虚拟机指令,有的教科书上会成为混合型或者半编译型。
  • 像Python和lua这样就更不好分了,可以直接解释源代码运行,也可以编译为虚拟机指令然后再运行。
  • php编译之后的结果可以被Web Server缓存起来,甚至还可以先被翻译为C++,然后再编译。
  • .NET 的CLR运行时是Windows的组成部分,编译好的.NET 系列语言的代码直接生成可执行文件,然后被“直接”执行,看起来跟C没有什么太大的差别。
  • JavaScript可以被V8引擎编译为机器码然后执行,如果在node.js下,这个编译结果被缓存起来了,你说这跟编译好再执行的C有什么区别?-