运行时栈帧结构
栈帧:是用于支持虚拟机进行方法调用和方法执行的数据结构,存储了方法的局部变量表、操作数栈、动态连接和方法返回值等信息。每一个方法从调用到执行的过程都对应着一个栈帧在虚拟机里面从入栈到出栈的过程
- 栈帧需要分配多少内存不会受运行期变量数据的影响,栈帧中局部变量表的大小和操作数栈的深度在编译程序代码时已经完全确定并写入方法的Code熟悉中
方法调用
- 静态方法、私有方法、实例构造器、父类方法以及final方法在类加载的时候就会把符号引用解析为该方法的直接引用。
Human man = new Man();
- 上面的Human就称为变量的静态类型,也叫外观类型,Man则称为变量的实际类型
- 静态类型的变化仅仅在使用时发生,变量本身的静态类型不会改变,并且最终的静态类型在编译期是可知的;而实际类型变化的结果需要在运行期才可以确定
- 虚拟机在重载时是通过参数的静态类型而不是实际类型作为重载版本的判断依据
- 所有依赖静态类型来定位方法执行版本的分派动作称为静态分派。静态分派发生在编译阶段,典型应用就是方法的重载
- 在运行期根据实际类型确定方法执行版本的分派过程称为动态分派。动态分派发生在程序运行期,典型应用是方法的重写。
- 动态分派的过程底层是invokevirtual指令的动态查找过程,而invokevirtual指令动态查找方法的第一步就是在运行期确定方法接收者的实际类型,然后在实际类型中去查找对应的方法,找不到再去父类中查找。
基于栈的字节码解释执行引擎
- java编译器输出的指令流,基本上是一种基于栈的指令集架构
- 基于栈的指令集的优点是可移植、代码相对紧凑、编译器实现更加简单等
- 栈架构指令集的缺点是执行速度相对稍慢,主要原因是:出栈入栈操作本身产生相当多的指令数量以及频繁的内存访问
编译期优化
- 将局部变量声明为final对运行期没有影响,变量的不变形仅仅由编译器在编译期间保障
- 泛型的类型擦除仅仅是对方法表的Code属性中的字节码进行擦除,实际上元数据中还是保留了泛型信息,这也是我们能通过反射手段取得参数化类型的根本依据
- 遍历循环需要被遍历的对的类实现Iterable接口是因为编译后被还原成了迭代器的实现
- 包装类的“==”运算在不遇到算数运算的情况下不会自动拆箱,equals方法不处理数据转型的关系
网友评论