首先,需要明确,在Class中,所有的方法都是一个符号引用,并非真实的方法调用入口。那么方法引用是怎么调用到真实的方法呢?
1.解析
(1).在类加载阶段,一部分符号引用会直接得到一个确定版本的,并且在使用过程中不会发生变化的方法。这种符号引用在解析阶段就会对应到实际的方法
(2).哪些方法会被解析?
1).父类方法
2).私有方法
3).<init>实例化方法
4).静态方法
5).被final修饰的方法
2.分派
(1).静态分派:根据静态类型定位方法执行版本的分派动作。经典:重载
(2).动态分派:根据运行时实际类型定位方法执行版本的分派动作。经典:重写
==>动态分派的过程:
1).栈顶第一个元素指向的对象实际类型
2).如果就是需要的方法,校验权限,通过则结束;不通过则报错
3).如果没找到,就自下而上去父类查找
4).如果都没查找到,报错
(3).返回值和参数成为宗量。
==>静态分派需要关注参数和返回值,所以静态多分派
==>动态分派仅需要关注返回值,所以动态单分派
3.实际分派
因为虚拟机中动态分派的动作很频繁,所以虚拟机在执行分派时,会做一些优化。
给父类和子类创建虚拟表,如果子类没有重写父类,那么表的入口和父类一样;如果子类重写了父类的方法,那么子类入口则会指向重写的地方
4.动态调用
(1).引导方法+方法类型+名称
(2).具体过程:
调用MethodHandles&Lookup的findStatic()方法,产生MethodHandle。然后用它创建一个ConstantCallSite对象。最后这个对象返回给虚拟机指令实现对方法的调用