目录
? ? ? ? 最近在学习Java虚拟机(JVM: Java Virtual Machine),在学习过程中,再一次学习了JVM的平台无关性这一特性,此外也了解到了虚拟机的另外一种中立特性 --- 语言无关性,下面进行简单介绍:
? ? ? ? 我们都知道Java语言一直以“一次编写,到处运行(Write Once, Run Anywhere)”著称,那么为什么Java语言可以有这样的特性呢?我们来聊一聊。
? ? ? ? 任何语言(包括高级语言和低级语言)想要被计算机执行,都必须被最终转换成计算机可以识别的二进制格式(即:把我们编写的程序编译成二进制本地机器码 Native Code),即计算机只认识的0和1。
? ? ? ? 假如没有JVM,我们来看看Java程序如何在计算机上运行起来:
? ? ? ? 设想这样一个场景,小明在Windows电脑上使用Java编写了一个程序,然后使用Java语言的编译器直接把Java源代码编译成Windows操作系统和其对应的硬件平台上的二进制本地机器码(Native Code),然后Windows电脑就可以运行我们写的程序了。如下图:
? ? ? ? 这时小明又装了一个linux系统,他想把上面编译好的二进制字节码放到Linux系统中运行,如下图:
? ? ? ? ?那么只能针对Linux系统,再开发一个针对Linux系统上的Java语言编译器,把Java源码编译成Linux硬件平台可以识别并执行的二进制字节码指令,如下图:
? ? ? ? 那么问题来了,如果再有另一个操作系统呢,还需要再针对这个操作系统再开发一个编译器?那么我们为什么不这样呢?如下图:
? ? ? ? ?上图说明了一件事,Java语言是平台无关性的语言,而这个平台无关性是由不同平台对应的Java虚拟机,即JVM来支撑的。换句话说,Java虽然是平台无关的,但是虚拟机(JVM)却是平台相关的,即不同操作系统需要对应不同的JVM。如下图是Oracle官网提供的不同操作系统对应的JDK,JDK里面包含了JVM:
? ? ? ? 下面在总结下Java的平台无关性是怎么实现的。
? ? ? ? 已经知道在计算机中真正执行的是由0和1组成的二进制文件。而我们通常开发使用的C,C++和Java等都是高级语言,如果要让计算机识别Java代码,就需要把Java开发的源程序“翻译”成二进制机器码,这个"翻译"的过程称为编译。执行编译这一过程的工具叫编译器。在Java中,要把Java代码编译成二进制字节码,需要经过两个步骤:(1)前端编译和后端编译。
? ? ? ? 前端编译主要指和源语言有关但和目标机器无关的部分,比如我们熟悉的javac,以及Eclipse,Idea等IDE中内置的前端编译器,都是为了把xxx.java源码编译成.class字节码。
? ? ? ? 后端编译就是将中间代码翻译成机器码,在Java中,这一步是通过JVM实现的。所以,虽然Java是平台无关的,但是虚拟机却是平台相关的,不同操心系统需要对应不同的JVM。?
? ? ? ? Java虚拟机除了具有平台无关性的特性外,还有另外一种中立特性:语言无关性。在Java技术发展之初,设计者们就曾经考虑过并实现了让其他语言运行在Java虚拟机之上的可能性,他们在发布规范文档的时候,也刻意把Java的规范拆分成了《Java语言规范》(The Java Language Specification)及《Java虚拟机规范》(The Java Virtual Machine Specification)两部分。如今,商业企业和开源机构已经在Java语言之外发展出一大批运行在Java虚拟机之上的语言,如Kotlin, Clojure, Groovy, JRuby, JPython, Scala等。
? ? ? ? 实现语言无关性的基础仍然是虚拟机和字节码存储格式。Java虚拟机不与包括Java语言在内的任何程序语言绑定,它只与“Class 文件” 这种特定的二进制文件格式所关联,Class文件种包含了Java虚拟机指令集、符号表以及若干其它辅助信息。?
? ? ? ? 基于安全方面的考虑,《Java虚拟机规范》种要求在Class文件必须应用许多强制性的语法和结构化约束,但图灵完备的字节码格式,保证了任意一门功能性语言都可以表示为一个能被Java虚拟机所接受的有效的Class文件。作为一个通用的、与机器无关的执行平台。任何其它语言的实现者都可以将Java虚拟机作为他们语言的运行基础,以Class文件作为他们产品的交付媒介。例如使用Java编译器可以把Java代码编译为存储字节码的Class文件,使用JRuby等其它语言的编译器一样也可以把他们的源程序代码编译成class文件。虚拟机丝毫不关心Class的来源是什么语言,它与程序之间的关系如下图: