在活动线程中,只有栈顶的栈时有效的,称为 当前栈帧 ,与这个栈帧相关联的方法称为 当前方法 。下面对栈帧的4个主要部分进行分析。
存放方法参数和方法内部定义的局部变量
一些细节:
boolean、byte、char、short、int、float、reference、returnAddress
占一个Slot; long、double
占两个Slot,是非原子的,但它是 线程安全
的,因为它是栈中的,是线程私有的。 this
。 优点:可移植性、代码更加紧凑、编译器实现更紧凑。确定就是速度更慢。
指向运行时常量池中该栈帧所属方法的引用,这个引用的为了支持方法调用过程的动态连接。具体内容在下面的方法调用中解释。
方法退出(也就是 当前栈帧出栈 )的两种方式:
return
方法调用不等同于方法的执行,方法调用阶段唯一的任务就是确定被调用方法的版本。说白了就是找方法,方法唯一就直接确定( 解析 )。方法不唯一: 重载(静态分配)、重写(动态分配)
调用目标在程序代码写好、编译器进行编译时就确定好的。这类方法时调用称为解析。是静态的。
非虚方法:静态方法、私有方法、实例构造器、父类方法、final方法。它们都是采用解析调用。反之其它就是虚方法。
Human man = new Man();
Human
是静态类型(外观类型), Man
是实际类型
依赖静态类型来定位方法执行的版本的分配动作称为静态分配。最典型的应用是方法重载。
依赖实际类型来定位方法执行的版本的分配动作称为动态分配。最典型的应用是方法重写。
一个测试例子:
public class MixTest { static class Human{ } static class Man extends Human{} static class Woman extends Human{} public static class Father { public void choice(Human arg) { System.out.println("father choose human"); } public void choice(Man arg) { System.out.println("father choose man"); } public void choice(Woman arg) { System.out.println("father choose woman"); // 和同一类里的同名方法是重载关系 } } public static class Son extends Father { public void choice(Human arg) { System.out.println("son choose human"); } public void choice(Man arg) { System.out.println("son choose man"); // 和父类的同名同参数方法是重写关系 } public void choice(Woman arg) { System.out.println("son choose woman"); } } public static void main(String[] args) { Human woman = new Woman(); Man man = new Man(); Father father = new Father(); Father son = new Son(); father.choice(woman); // 重写:对象类型选Father(实际类型) 重载:参数类型选 Human(静态类型) son.choice(man); // 重写:对象类型选Son(实际类型) 重载:参数类型选 Man(静态类型) } } /* 程序输出: father choose human son choose man */ 复制代码