执行原理
Java 虚拟机中关于方法重写的判定基于方法描述符,如果子类定义了与父类中非私有、非静态方法同名的方法,只有当这两个方法的参数类型以及返回类型一致,Java 虚拟机才会判定为重写
理解多态:
- 多态有编译时多态和运行时多态,即静态绑定和动态绑定
- 前者是通过方法重载实现,后者是通过重写实现(子类覆盖父类方法,虚方法表)
- 虚方法:运行时动态绑定的方法,对比静态绑定的非虚方法调用来说,虚方法调用更加耗时
方法重写的本质:
- 找到操作数栈的第一个元素所执行的对象的实际类型,记作 C
- 如果在类型 C 中找到与描述符和名称都相符的方法,则进行访问权限校验(私有的),如果通过则返回这个方法的直接引用,查找过程结束;如果不通过,则返回 java.lang.IllegalAccessError 异常
IllegalAccessError:表示程序试图访问或修改一个属性或调用一个方法,这个属性或方法没有权限访问,一般会引起编译器异常。如果这个错误发生在运行时,就说明一个类发生了不兼容的改变 - 找不到,就会按照继承关系从下往上依次对 C 的各个父类进行第二步的搜索和验证过程
- 如果始终没有找到合适的方法,则抛出 java.lang.AbstractMethodError 异常
虚方法表
在虚拟机工作过程中会频繁使用到动态绑定,每次动态绑定的过程中都要重新在类的元数据中搜索合适目标,影响到执行效率。为了提高性能,JVM 采取了一种用空间换取时间的策略来实现动态绑定,在每个类的方法区建立一个虚方法表(virtual method table),实现使用索引表来代替查找,可以快速定位目标方法
- invokevirtual 所使用的虚方法表(virtual method table,vtable),执行流程
- 先通过栈帧中的对象引用找到对象,分析对象头,找到对象的实际 Class
- Class 结构中有 vtable,查表得到方法的具体地址,执行方法的字节码
- invokeinterface 所使用的接口方法表(interface method table,itable)
虚方法表会在类加载的链接阶段被创建并开始初始化,类的变量初始值准备完成之后,JVM 会把该类的方法表也初始化完毕