栈帧是虚拟机栈中的栈元素,栈帧存储方法的局部变量表,操作数栈,动态链接和方法返回地址信息,附加信息。
局部变量表:
局部变量表单位成为变量槽(Slot),一个Slot存储32位以内的数据类型,对于long和double,64位,可分为两个Slot存储,由于虚拟机栈是线程独有的,所以这么存储是安全的。
Slot是复用的,当某一Slot数据超出作用范围,它就可以被复用。
对于实例方法,局部变量表索引为0的位置是指向该方法所属的实例的。
局部变量必须赋初始值,局部变量没有类加载准备那一阶段。
操作数栈
基于栈的指令和基于寄存器的指令对比:
基于栈:优点是不依赖具体硬件实现;缺点是同一动作,翻译后的指令数目多,访问内存影响速度。
动态连接
栈帧会包含指向运行时常量池中该栈帧所属方法的引用,除了静态方法,私有方法,实例构造器和父类方法(还有final方法)会在解析阶段就将符号引用转化为直接引用外,其他符号引用将在运行期间将符号引用转换为直接引用。
方法返回地址
- 恢复上层方法的操作数栈和局部变量表
- 将该方法的计算结果压入上层方法的
- PC计数器指向下一条指令
附加信息
例如调试信息等。
方法调用
关于方法调用,注意以下几点:
- 重载是静态分派,根据引用类型来判断,不管实际类型;多宗量
public class F{}
public class S1 extends F{}
public class S2 extends F{}
public class Test{
public void fun(F){System.out.println("F");}
public void fun(S1){System.out.println("S1");}
public void fun(S2){System.out.println("S2");}
public static void main(String[] args){
F f1 = new S1();
F f2 = new S2();
Test t = new Test();
t.fun(f1);
t.fun(f2);
}
}
运行结果:
F
F
- 重写是动态分派,单宗量
这就不举例了,会根据实际类型来选取将要执行哪个方法。