先做一个最简程序;然后反汇编一下;
public class hello {
public static void main(String[] args) {
int a = 101;
}
}
然后来学习几个jvm的基本指令;
第一条是aload_0,似乎每个java控制台程序反汇编了都是这句;
aload_<n>
从局部变量表加载一个reference类型值到操作数栈中;
<n>代表当前栈帧中局部变量表的索引值;
然后是invokespecial #1;
invokespecial:用于调用一些需要特殊处理的实例方法、包括实例初始化方法、私有方法和父类方法;
java.lang.object;Object类是所有Java类的祖先;
那么这句是本程序的类实例的初始化;
int a = 101;
反汇编后一共有2句;
bipush 101
istore_1
bipush
将一个byte类型数据入栈;
格式:bipush byte
将立即数byte带符号扩展为一个int类型的值value,然后将value入栈到操作数栈中;
istore_<n>
将一个int类型数据保存到本地变量表中;
<n>必须是一个指向当前栈帧局部变量表的索引值;
也就是把101入栈到操作数栈,然后放入本地变量表;因为代码中定义的 a 是一个本地变量;
初步认识是,虚拟机指令是一种类汇编的语言,它有加载和存储指令;
加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈之间来回传输;
汇编MOV指令是数据传送指令,在寄存器和内存地址之间传送数据;虚拟机的加载和存储指令是在局部变量表和操作数栈之间传送数据;
局部变量表,操作数栈,这些是JVM运行时定义的一些内存区域;
再看一个;
public class hello2 {
public static void main(String[] args) {
int a11 = -2147483647;
System.out.println(a11);
int a16 = -32769;
System.out.println(a16);
int a07 = 32768;
int a08 = 65535;
int a09 = 65536;
int a10 = 2147483647;
System.out.println(a10);
}
}
对class反汇编后如下;
用到的相关指令如下;
bipush
将一个byte类型数据入栈;
格式:bipush byte
将立即数byte带符号扩展为一个int类型的值value,然后将value入栈到操作数栈中;
istore_<n>
将一个int类型数据保存到本地变量表中;
<n>必须是一个指向当前栈帧局部变量表的索引值;
ldc
从运行时常量池中提取数据并压入操作数栈;
格式:ldc index
index是一个无符号byte类型数据,用作当前类的运行时常量池的索引;
getstatic
获取类的静态字段值;
格式:getstatic indexbyte1 indexbyte2
indexbyte1和indexbyte2用于构建一个指向当前类的运行时常量池的索引值;
iload_<n>
从局部变量表加载一个int类型值到操作数栈中;
<n>代表一个当前栈帧中局部变量表的索引值;
invokevirtual:用于调用对象的实例方法,根据对象的实际类型进行分派(虚方法分派),这也是Java语言中最常见的方法分派方式;
一开始是ldc,从反汇编代码看,自己程序给出的数值,像 int a07 = 32768 这样的,32768这些值被放入了运行时常量池;当要用到时把数据压入操作数栈;
然后是istore;把值保存到本地变量表;
然后getstatic,不了解;
运行时常量池,是JVM运行时定义的一个内存区域;
然后是iload;把数值加载到操作数栈;
然后是invokevirtual;这就是调用println方法了;
不是很了解;先看一下吧;
运行时常量池简介
运行时常量池(Runtime Constant Pool),它是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到常量池中。
运行时常量是相对于常量来说的,它具备一个重要特征是:动态性。当然,值相同的动态常量与我们通常说的常量只是来源不同,但是都是储存在池内同一块内存区域。Java语言并不要求常量一定只能在编译期产生,运行期间也可能产生新的常量,这些常量被放在运行时常量池中。这里所说的常量包括:基本类型包装类(包装类不管理浮点型,整形只会管理-128到127)和String(也可以通过String.intern()方法可以强制将String放入常量池)
;Compiled from "hello.java"
public class hello {
public hello();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 101
2: istore_1
3: return
}
;Compiled from "hello2.java"
public class hello2 {
public hello2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // int -2147483647
2: istore_1
3: getstatic #3 // Field java/lang/System.out:Ljava/
io/PrintStream;
6: iload_1
7: invokevirtual #4 // Method java/io/PrintStream.printl
n:(I)V
10: ldc #5 // int -32769
12: istore_2
13: getstatic #3 // Field java/lang/System.out:Ljava/
io/PrintStream;
16: iload_2
17: invokevirtual #4 // Method java/io/PrintStream.printl
n:(I)V
20: ldc #6 // int 32768
22: istore_3
23: ldc #7 // int 65535
25: istore 4
27: ldc #8 // int 65536
29: istore 5
31: ldc #9 // int 2147483647
33: istore 6
35: getstatic #3 // Field java/lang/System.out:Ljava/
io/PrintStream;
38: iload 6
40: invokevirtual #4 // Method java/io/PrintStream.printl
n:(I)V
43: return
}