执行引擎是Java虚拟机最核心的组成部分之一,,全部的Java虚拟机的执行引擎都是一致的:
输入:字节码文件
处理:字节码解析
输出:执行结果java
在介绍虚拟机栈时就提到,每一个方法在执行的同时都会建立一个栈帧用于存储局部变量表、操做数栈、动态连接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。栈帧中须要多大的局部变量表和多深的操做数栈在编译代码的过程当中已经彻底肯定,并写入到方法表的Code属性中。在活动的线程中,位于当前栈顶的栈帧才是有效的,执行引擎运行的全部字节码指令只针对当前栈帧进行操做。jvm
一切方法调用在Class文件里面都是一个常量池中的符号引用。在类加载解析阶段,可能会将其中一部分符号引用转化为直接引用,也有可能会在初始化阶段以后再开始,取决于方法在运行以前是否有有肯定的调用版本,且在运行期间不变。
在Java中符合编译器可知,运行期不可变的方法,主要包括静态方法和私有方法两大类,它们都不可能经过某些方式重写其余版本,所以它们都适合在类加载阶段进行解析
JVM提供了5条方法调用字节码:
invokestatic:调用静态方法
invokespecial:调用实例构造器方法、私有方法和父类方法
invokevirtual:调用全部的虚方法
invokedynamic:运行时动态解析出调用点限定符所引用的方法,再执行该方法
只要能被invokestatic和invokespecial指令调用的方法,均可以在解析阶段中肯定惟一的调用版本,它们在类加载时会把符号引用解析为该方法的直接引用。
示例:
spa
public class Person {
public static void sayHello() {
System.out.println("hello world");
}
public static void main(String[] args) {
sayHello();
}
}
复制代码
javap -verbose查看
public class Person {
public static void main(String[] args) {
new Person();
}
}
复制代码
javap -verbose查看
经过invokestatic和invokespecial指令调用的方法称为非虚方法,与之相反,其余方法称为虚方法(除去final方法),虚方法的调用是一个分派的过程,有静态也有动态,可分为静态单分派、静态多分派、动态单分派和动态多分派。线程
全部依赖静态类型来定位方法执行版本的分派,静态分派的典型应用是方法重载,静态分派发生在编译阶段,所以静态分派的动做不禁虚拟机执行。eg:3d
public class Person {
public void sayHello(Object obj){
System.out.println("hello Object");
}
public void sayHello(String str){
System.out.println("hello String");
}
public static void main(String[] args) {
Person p = new Person();
Object obj = new String();
p.sayHello(obj);
}
}
复制代码
结果:code
hello Object
复制代码
相对于变量obj,Object是其静态变量,String是其实际变量,在编译阶段,Java编译器会根据参数的静态类型决定调用哪一个重载版本。用javap -verbose再看下
cdn
动态分派根据实际类型肯定方法执行版本对象
public class Person {
public static void main(String[] args) {
Object p = new Person();
Object obj = new String("比利时");
System.out.println(obj.toString());
System.out.println(p.toString());
}
}
复制代码
输出blog
比利时
jvm.Person@63ce0e18
复制代码
同一个静态类型,调用toString方法,结果彻底不一样,缘由就是由于这两个变量的实际类型不一样。经过java -verbose 查看字节码指令
继承
《深刻理解Java虚拟机》