在活动线程中,只有栈顶的栈时有效的,称为 当前栈帧 ,与这个栈帧相关联的方法称为 当前方法 。下面对栈帧的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
*/
复制代码