执行过程如下
1、为main方法创建栈帧:
局部变量表长度为2,slot0存放参数args,slot1存放局部变量Student s,操作数栈最大深度为5。
2、new#7指令,在java堆中创建一个Student对象,并将其引用值放入栈顶。
3、初始化一个对象(通过实例构造的方式)
up指令:复制栈顶的值,然后将复制的结果入栈。
bipush 23:将单字节常量值23入栈。
ldc #8:将#8这个常量池中的常量即”dqrcsc”取出,并入栈。
ldc #9:将#9这个常量池中的常量即”20150723”取出,并入栈。
4、invokespecial #10:调用#10这个常量所代表的方法,即Student.()这个方法,这步是为了初始化对象s的各项值
《init》()方法,是编译器将调用父类的《init》()的语句、构造代码块、实例字段赋值语句,以及自己编写的构造方法中的语句整合在一起生成的一个方法。保证调用父类的《init》()方法在最开头,自己编写的构造方法语句在最后,而构造代码块及实例字段赋值语句按出现的顺序按序整合到《init》()方法中。
注意到Student.《init》()方法的最大操作数栈深度为3,局部变量表大小为4。
此时需注意:从dup到ldc #9这四条指令向栈中添加了4个数据,而Student.()方法刚好也需要4个参数:
public Student(int age, String name, String sid){
super(age,name);
this.sid = sid;
}1234567
虽然定义中只显式地定义了传入3个参数,而实际上会隐含传入一个当前对象的引用作为第一个参数,所以四个参数依次为this,age,name,sid。
上面的4条指令刚好把这四个参数的值依次入栈,进行参数传递,然后调用了Student.《init》()方法,会创建该方法的栈帧,并入栈。栈帧中的局部变量表的第0到4个slot分别保存着入栈的那四个参数值。
创建Studet.《init》()方法的栈帧:
Student.《init》()方法中的字节码指令:
aload_0:将局部变量表slot0处的引用值入栈
aload_1:将局部变量表slot1处的int值入栈
aload_2:将局部变量表slot2处的引用值入栈
invokespecial #1:调用Person.()方法,同调用Student.过程类似,创建栈帧,将三个参数的值存放到局部变量表等,这里就不画图了……
从Person.()返回之后,用于传参的栈顶的3个值被回收了。
aload_0:将slot0处的引用值入栈。
aload_3:将slot3处的引用值入栈。
putfield #2:将当前栈顶的值”20150723”赋值给0x2222所引用对象的sid字段,然后栈中的两个值出栈。
return:返回调用方即main()方法,当前方法栈帧出栈。
重新回到main()方法中,继续执行下面的字节码指令:
astore_1:将当前栈顶引用类型的值赋值给slot1处的局部变量,然后出栈。