java虚拟机基础知识大全 java虚拟机运行原理( 七 )


Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数 。这些符号引用一部分会在类加载阶段或者第一次使用的时候就被转化为直接引用,这种转化被称为静态解析 。另外一部分将在每一次运行期间都转化为直接引用,这部分就称为动态连接 。
当一个方法开始执行后,只有两种方式退出这个方法 。
第一种方式是执行引擎遇到任意一个方法返回的字节码指令,这时候可能会有返回值传递给上层的方法调用者(调用当前方法的方法称为调用者或者主调方法),方法是否有返回值以及返回值的类型将根据遇到何种方法返回指令来决定,这种退出方法的方式称为“正常调用完成”() 。
另外一种退出方式是在方法执行的过程中遇到了异常,并且这个异常没有在方法体内得到妥善处理 。这种退出方法的方式称为“异常调用完成()” 。一个方法使用异常完成出口的方式退出,是不会给它的上层调用者提供任何返回值的 。
无论采用何种退出方式,在方法退出之后,都必须返回到最初方法被调用时的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层主调方法的执行状态 。
方法正常退出时,主调方法的PC计数器的值就可以作为返回地址,栈帧中很可能会保存这个计数器值 。而方法异常退出时,返回地址是要通过异常处理器表来确定的,栈帧中就一般不会保存这部分信息 。
一般会把动态连接、方法返回地址与其他附加信息全部归为一类,称为栈帧信息 。
方法调用并不等同于方法中的代码被执行,方法调用阶段唯一的任务就是确定被调用方法的版本(即调用哪一个方法),暂时还未涉及方法内部的具体运行过程 。
所有方法调用的目标方法在Class文件里面都是一个常量池中的符号引用,在类加载的解析阶段,会将符合“编译期可知,运行期不可变”的方法符号引用转化为直接引用 。换句话说,调用目标在程序代码写好、编译器进行编译那一刻就已经确定下来 。这类方法的调用被称为解析() 。
静态方法、私有方法、实例构造器、父类方法4种,再加上被final修饰的方法(尽管它使用指令调用),这5种方法调用会在类加载的时候就可以把符号引用解析为该方法的直接引用 。这些方法统称为“非虚方法”(Non-),与之相反,其他方法就被称为“虚方法”( ) 。
英文一般是“”,所以其实是个动态概念
class{
class Human{
}
class ManHuman{
}
class WomanHuman{
}
void (Human guy){
.out.("Hello guy");
}
void (Man guy){
.out.("Hello ");
}
void (Woman guy){
.out.("Hello lady");
}
void main([] args){
Human man = new Man();
Human woman = new Woman();
= new ();
.(man);
.(woman);
}
}
运行结果
Hello guy
Hello guy
Human hu = new Man():
面代码中的“Human”称为变量的静态类型( Type)或者外观类型( Type),后面的“Man”则称为变量的实际类型( Type),静态类型和实际类型在程序中都可以发生一些变化,区别是静态类型的变化仅仅在使用时发生,变量本身的静态类型不会被改变,并且最终的静态类型是编译期可知的;而实际类型变化的结果在运行期才可确定,编译期在编译程序的时候并不知道一个对象的实际类型是什么?如下面的代码:
//实际类型变化
Human man = new Man();
man = new Woman();
//静态类型变化
sd.((Man)man);