2. Java字节码
2021-07-22 本文已影响0人
轻轻敲醒沉睡的心灵
1. 简单查看字节码
上节说道Java是跨平台的语言,是因为运行Java的虚拟机JVM是能跨平台的,Java依赖于它,也就能跨平台了。我们写的Java源代码虚拟机不能识别,要经过编译后会变成.class文件,才能够被虚拟机加载。
我们看一下java文件编译,以及字节码文件:
javac Demo.java
javap -c Demo.class
Java源文件
public class Demo {
public static void test() {
int n = 1;
int m = 2;
int t = (n + m) * 5;
System.out.print(t);
}
}
字节码
由上图可以看出,在字节码中,
test()
方法分步用很多指令(iconst、istore、iload)来操作数据。JVM 是一台基于栈的计算机器。
每个线程都有一个独属于自己的线程栈(JVM Stack),用于存储栈帧(Frame)。每一次方法调用,JVM 都会自动创建一个栈帧。栈帧由操作数栈, 局部变量数组以及一个 Class 引用组成。
test()
方法中的局部变量都在同一栈针中。
2. 字节码
从上面的内容可以看出,字节码文件 就是把我们写的Java源文件编译成Jvm虚拟机可读的 一些指令集。
Java bytecode 由单字节(byte)的指令组成,理论上最多支持 256 个操作码(opcode)。实际上 Java 只使用了200左右的操作码, 还有一些操作码则保留给调试操作。
2.1 指令分类
字节码中的指令,根据他们的性质,主要分为四个大类:
- 栈操作指令,包括与局部变量交互的指令 -- iconst、istore、iload等
- 程序流程控制指令
- 对象操作指令,包括方法调用指令 -- invokevirtual等
- 算术运算以及类型转换指令 -- iadd、imul等
2.2 方法调用的指令:
-
invokestatic
,顾名思义,这个指令用于调用某个类的静态方法,这是方法调用指令中最快的一个。
-
-
invokespecial
, 用来调用构造函数,但也可以用于调用同一个类中的 private 方法, 以及可见的超类方法。
-
-
invokevirtual
,如果是具体类型的目标对象,invokevirtual 用于调用公共,受保护和package 级的私有方法。
-
-
invokeinterface
,当通过接口引用来调用方法时,将会编译为 invokeinterface 指令。
-
-
invokedynamic
,JDK7 新增加的指令,是实现“动态类型语言”(Dynamically Typed Language)支持而进行的升级改进,同时也是 JDK8 以后支持 lambda 表达式的实现基础。
-