对于执行引擎来说,在活动线程中,只有栈顶的方法在运行,因此也只有位于栈顶的栈帧才是生效的,也叫做当前栈帧。
用于存放方法参数和方法内部定义的局部变量,以变量槽为最小单位,在编译为Class文件后,在方法的Code属性的max_locals数据项确定了该方法的最大容量。局部变量表(非static)中第0个索引默认存储this,方法体中的拜年了超过其作用域后,其所占用的变量槽会被重用。
在方法的Code属性中max_stacks数据项中规定了操作数栈的最大深度。在方法的执行过程中, 会有各种字节码指令往操作数栈中写入和提取内容, 也就是出栈和入栈操作。
在类加载的解析阶段,会将一部分的符号引用转化为直接引用。调用不同类型的方法,字节码指令集中设计了不同的指令。
<init>()
方法、 私有方法和父类中的方法。invokestatic和invokespecial所对应的被调用的四种方法加上被invokevirtual调用的被final修饰的方法称之为非虚方法,在类加载时可以把这些方法的符号引用解析为直接引用。与之相反的被称之为虚方法。
分派分为静态分派与动态分派,对应这java语言中的重载和重写。
变量类型分为静态类型和实际类型。Map map = new HashMap()
这其中,Map为变量map的静态类型,HashMap为实际类型。
虚拟机在重载时,是通过参数的静态类型而不是实际类型确定使用哪个重载的方法。在重写时,通过参数的动态类型确定使用哪种方法,这是由于invokevirtual指令执行的第一步是在运行期确定接受者的实际类型。需要明确的一点是,只有方法是可以在子类中重写的,对于字段而言,子类的字段将会遮住父类的同名字段。
根据方法的宗量(方法接受者和参数)数量是一个还是多个,确定分派是但分派还是多分派。静态分派为多分派,虚拟机会考虑方法的静态类型和方法参数两个宗量。动态分派属于单分派类型,因为影响虚拟机选择的因素只有该方法的接受者的实际类型。
动态分派是执行非常频繁的动作,虚拟机对此也做出了一些优化:在方法区中建立一个虚方法表,虚方法表中存放着各个方法的实际入口地址,使用虚方法表许艺娜来代替元数据查找以提高性能。