1.write once, run anywhere的基石
java语言有一个很重要的特性:一次编写,到处运行。即我们编写的代码,能够在不同的操作系统平台上运行。这里就引发出一个问题,不同的操作系统有不同的硬件实现和指令集,同一份代码如果要在这些不同的机器上运行,那么就要将这些代码翻译成与机器指令集对应的二进制文件,才能保证运行结果的一致性。
java使用虚拟机去屏蔽操作系统的差异性,其原理如图所示。我们编写的Java程序在被编译后,以class文件的形式被存放在磁盘、内存、网络...中,然后由jvm进行加载,并解释执行。字节码文件相当于是对我们所编写程序的二进制描述,但他并不能被操作系统直接执行,而是由jvm解释成对应系统的指令,再进行执行。因此java程序虽然会被编译,但仍属于解释型语言。另一方面,现在的JVM为了效率,都有一些JIT优化。它又会把.class的二进制代码编译为本地的代码直接运行,所以,它也不完全是一门解释型语言。
处处运行的基石
2. JDK,JRE,JVM的关系
JDK是支持java语言开发的最小支持环境,包含了java语言,工具即其api,JRE。
JRE是运行时环境,能够支持java语言的运行。包含了JVM和Java核心类库,但不包含开发工具(将.java编译成.class文件的编译器、调试器等)
JVM是将.class文件加载到内存并解释执行的组件,显然它是java体系的核心部件。
组件关系
3. JVM的功能及指令集基础
JVM中实现了对java指令的加载、解释、执行。
其指令集是基于栈的架构而非基于寄存器的架构。也就是说,指令的操作数依赖于操作数栈,而非操作数地址。
举个例子说明:
public class AddA {
public static void main(String[] args) {
int a = 2;
int b = 3;
int c = a + b;
}
}
...
对应的字节码指令
0 iconst_2 //2入栈
1 istore_1 //2出栈,并存放到局部变量表1位置
2 iconst_3 //3入栈
3 istore_2 //3出栈,并存放到局部变量表1位置
4 iload_1 //从局部变量表1位置读取操作数并入栈
5 iload_2 //从局部变量表2位置读取操作数并入栈
6 iadd // 弹栈并相加,将结果5压入操作数栈
7 istore_3 // 5出栈并存放到局部变量表3位置
8 return //方法返回
而基于寄存器的计算2+3则如图
基于寄存器:2+3
之所以java指令要依据栈来实现,主要原因是不同平台cpu架构不同,设计为基于寄存器的话,难以实现跨平台。
网友评论