JVM基本原理:JVM是如何执行方法调用的?

重载和重写

public class aa {    public static void invoke(Object obj, Object... args) { ​   } ​    public static void invoke(String a, Object obj, Object... args) { ​   } ​    public static void main(String[] args) {        invoke(null, 1);//2        invoke(null, 1, 2);//2        invoke(null, new Object[]{1});//手动绕开可变参数语法糖,调1   } }

选择重载方法

  1. 不考虑基本类型自动装拆箱,可变参数选取重载方法
  2. 1没找到,允许自动装拆箱,不允许可变参数情况下选择重载方法
  3. 2没找到,允许自动装拆箱和可变参数情况下选择重载方法

找到多个:找最贴切的:参数类型继承关系

String是Object子类,Java编译器认为更贴切

父子类重载(非私有方法)

拨打10086->根据你所在地连接到当地客服

JVM的静态绑定和动态绑定

JVM怎么识别方法?

类名、方法名、方法描述符(方法参数,返回类型)

JVM和Java语言不同,JVM不限制名字和参数类型相同,但返回类型不同的方法出现在一个类,对于调用这些方法的字节码来说,由于字节码所附带的方法描述符包含返回类型,因此JVM能够准确识别目标方法

JVM判定重写基于方法描述符,如果子类父类非私有方法名字,只有参数类型和返回类型一致JVM才会判定为重写

Java语言重写,JVM不重写,编译器通过桥接方法实现Java中重写语义

重载区分在编译阶段完成,JVM不存在重载这一概念,因此重载也叫静态绑定(直接识别),或者编译时多态,重写被叫动态绑定(动态识别)

Java字节码调用指令5种:

  1. invokestatic:调用静态方法,JVM直接识别
  2. invokespecial:调用私有实例方法。构造器,super实例方法,构造器,所实现接口的default方法,JVM直接识别
  3. invokevirtual:非私有实例方法,动态识别
  4. invokeinterface:接口方法,动态识别
  5. invokedynamic:动态方法

import java.util.Random; interface Customer {    boolean isVIP(); } ​ class Merchants {    public double discountPrice(double price, Customer customer) {        return price * 0.8d;   } } ​ class profiteers extends Merchants {    @Override    public double discountPrice(double price, Customer customer) {        if (customer.isVIP()) {//invokeinterface            return price * 价格歧视();//invokestatic       } else {            return super.discountPrice(price, customer);//invokespecial       }   } ​    public static double 价格歧视() {        return new Random()//invokespecial,Random构造器               .nextDouble();//invokevirtual   } }

例外:JVM能确定目标方法只有一个,final[3] [4],直接识别

调用符号引用

存储在class文件的常量池中,根据目标方法是否为接口方法,这些引用可分为接口符号引用和非接口符号引用

  • 非接口引用

假设指向类C,JVM:

  1. 在C中找符合名字及描述符的方法
  2. 没找到,在C父类找,until Object类
  3. 没找到,在C直接实现或间接实现的接口找,目标方法必须是非私有,非静态,如果目标方法在间接实现的接口中,则需要满足C和此接口直接没有其他符合条件的目标方法,如果有多个,任意返回一个
  • 子类静态方法会隐藏父类中同名,同描述符的静态方法
  • 静态方法可以通过子类调用
  • 接口符号引用,假设指向I,JVM
  1. 在I中找符号名字和描述符的方法
  2. 没找到,在Object类中公有实例方法中找
  3. 没找到,在I的超接口找,目标方法非私有,非静态

符号引用->实际引用

静态绑定方法:实际引用是一个指向方法的指针

动态绑定方法:实际引用是一个方法表的索引