Class文件二进制字符流通过类加载器和虚拟机加载到内存(方法区)完成在内存上的布局和初始化后,虚拟机字节码执行引擎就可以执行相关代码实现程序所定义的功能。虚拟机执行引擎执行的对象是方法(均特指非本地方法),方法是
着一个程序所定义的一个功能的载体,实现预定的业务功能或者特定的功能等。虚拟机执行引擎就是执行程序方法的一个引擎,一个类的信息通过方法承载了它所担负的功能职责,程序的执行就是一个个方法的执行和相互调用。
方法的内容有:方法名,参数列表,返回值,内部定义的局部变量,方法的可见性,方法内部的执行操作和符号引用等等。虚拟机执行引擎要执行方法,首先就需要用单独的数据结构来存放定义方法签名信息和内部定义的局部变量等。然后
方法内部引用到了外部类或者方法等信息就需要进行相关符号引用的解析,而且在允许方法出现重载的情况下还要特定的机制用来确定最终要执行的方法版本。最后还要告诉底层硬件将要如何执行预定的程序代码。
Java虚拟机内存内针对方法的执行专门划分了一个区域即虚拟机栈。虚拟机栈内通过栈帧结构来存储调用方法和执行方法需要的局部变量,操作数栈、方法返回值等,通过栈帧的出入栈来表示方法的执行顺序。
1、栈帧结构:虚拟机内如何存储方法的内容,方法如何在虚拟机内的表示
栈帧的结构也就是程序方法的结构,栈帧结构存储了方法的内容。栈帧的出栈入栈代表了方法的执行过程和方法执行模型。
栈帧组成 |
用途、作用、功能 |
特点 |
其他 |
局部变量表 | 变量值存储空间,用于存放方法需要的参数和局部变量 | 以变量槽Slot为最小单位,每个Slot存储特定类型的数据信息,且可重用 局部变量表内的变量在虚拟机类的加载过程中不进行系统默认值初始化。 |
静态方法: 实例方法:第0位索引存放方法所属对象实例的引用 |
操作栈 | 用于存放字节码操作指令执行所需要的操作数值和操作执行结果值 | 32位数据占用1个操作栈,64位数据占用两个操作栈 | |
动态连接 | 运行期将相关的符号引用转换为直接引用 | 静态连接:在类加载或者第一次使用的时候转换为直接引用 | 栈帧信息 |
返回地址 | 方法执行完成的结果值 | 栈帧信息 | |
附加信息 | 附加到栈帧上的一些信息 | 栈帧信息 |
2、方法的调用:解析方法的符号引用和确定方法的版本
(1)虚方法和非虚方法
只有在允许方法重载的情况下才有虚方法和非虚方法之分,因为在允许重载的情况下方法的版本不止一个,在方法的执行前需要特定的机制确定将要执行的方法版本。
非虚方法:能够在解析阶段(将符号引用转换为直接引用)确定方法执行版本的方法。在解析阶段能够确定方法版本的有:静态方法,私有方法,实例构造器,父类方法,final修饰的方法
虚方法:只有在运行期才能够最终确定方法执行版本的方法。
(2)解析
方法调用时,方法执行前将方法内的符号引用转换为直接引用的过程
解析调用时一个静态的过程,在编译期内就能够完全确定。类加载过程中解析阶段就会把涉及的符号引用直接转换为直接引用。
(3)分派
确定方法最终调用的版本的步骤。
1)静态分派和动态分派:
静态分派(编译期分派):在编译期根据静态类型来定位方法执行的版本的分配过程,因为静态类型在编译期可知.Java虚拟机方法重载的规则就是根据参数的静态类型确定最终执行的方法版本的。
动态分派(运行期分派):在运行期根据实际类型来确定最终执行的方法版本的分派过程
2)方法的重载和重写
3、虚拟机如何执行方法?虚拟机执行引擎的工作机制
(1)解释执行(通过解释器执行)
指令集 |
优点 |
缺点 |
应用情况 |
基于栈的指令集 | 可移植,代码相对紧凑、编译器实现简单 | 执行速度慢 | |
基于寄存器的指令集 | 受硬件约束大,不可移植性 | 执行速度快 | 主流物理机采用 |