JAVA虚拟机基本原理(二:JVM是如何执行方法调用的)

JVM是如何执行方法调用的

在java程序中,一个类中出现多个名字相同,并且参数也相同的方法,那么他们是无法编译通过的。

重载:

      在同一个类中定义名字相同的方法,但是参数的类型和个数不同,这些方法之间的关系就是重载。重载的方法在编译期就完成识别。具体到每一个方法调用,java编译器会根据所传入的参数的声明类型来选择重载方法。重载方法在编译阶段已经完成。

     选择过程分为三个阶段:

    1 不考虑对基本类型的自动拆装箱,以及可变长参数的情况下选取重载方法。

    2 上述情况下没有找到适配的方法,那么在允许自动拆箱的,不允许可变长参数的情况下选取重载方法。

    3 上述情况未找到适配的方法,那么在允许自动拆箱的,允许可变长参数的情况下选取重载方法。

重载也可以发生在父子类中。如果子类定义了与父类中非私有方法同名的方法,而且这两个方法的参数类型不同,那么在子类中,这两个方法构成了重载。

重写:

     父子类中如果两个方法都是静态的,那么子类的方法隐藏了父类的方法。如果这两个方法都不是静态的也不是私有的,方法名和参数类型相同,那么子类的方法重写了父类的方法。JAVA一个很重要的特性便是多态,方法重写就是多态的体现。允许子类继承父类的部分功能,也可以拥有自己独特的行为。

JVM的静态绑定和动态绑定:

        某些文章中也称重载为静态绑定,重写为动态绑定。静态绑定:JVM在解析时便能够直接识别目标方法。动态绑定:需要在运行过程中根据调用者的动态类型来识别目标方法。

       JVM识别虚拟机方法的关键在于类名,方法名以及方法描述符方法描述符是由方法的参数类型和返回类型构成的。同一个类中同时出现多个名字相同切描述符也相同的方法,那么JVM在验证阶段报错。JVM能够通过方法描述符准确的识别目标方法。

JVM中关于方法的重写的判定就是基于方法描述符的。也就是说,如果子类定义了与父类中非私有的,非静态的同名方法。那么只有当这两个方法的参数类型和返回方法一致,JVM才会判定重写。

JAVA字节码调用相关的指令:

     1 invokestatic: 调用静态方法。

     2 invokespecial: 调用私有实例方法,构造器,super调用父类的实例方法和构造器,和实现接口的默认方法。

     3 invokevirtual: 调用非私有实例方法。

     4 invokeinterface: 调用接口方法。

     5  invokedynamic: 调用动态方法。

调用指令的符号引用:

编译过程中,我们并不知道目标方法的具体内存地址,JAVA编译器会暂时用符号引用来表示该目标方法。符号引用包括目标方法所在的类或接口的名字,以及目标方法的文件名和方法描述符。

符号引用存储在class文件的常量池中。在执行使用符号引用的字节码前,JVM需要解释这些符号引用,并替换成实际引用。对于可以静态绑定的方法调用而言,实际引用是一个指向方法的指针。对于需要动态绑定的方法调用而言,实际引用是一个方法表的索引。

 

虚方法:

     java里所有非私有实例方法调用都会被编译成invokevirtual指令。而接口方法调用都会被编译成invokeinterface指令。这两种指令都属于JVM的虚方法调用。

静态绑定包括用于调用静态方法的invokestatic指令,和调用构造方法,私有实例方法以及超类非私有实例方法的invokeSpecial指令。

JVM根据调用者的动态类型,来确定虚方法调用的目标方法,这个过程称为动态绑定。JVM用一种空间换时间的策略来实现动态绑定。

 

方法表:

     类加载的准备阶段,除了静态字段的内存分配外,还会构造与该类相关联的方法表。这个数据结构是JVM实现动态绑定的关键所在。

     方法表本质是一个数组。每个数组元素指向一个当前类以及祖先类中非私有的实例方法。方法表满足俩个特质:1 子类方法表中包含父类方发表中所有方法。  2  子类方法在方法表中的索引值与所重写的父类方法的索引值相同。对于静态绑定的方法调用而言,实际引用将指向具体的目标方法。对于动态绑定的方法调用而言,实际引用则是方法表的索引值。在执行过程中,JVM将获取调用者的实际类型,并在该实际类型的虚方法表中,根据索引值获得目标方法。

     实际上,使用方法表的动态绑定与静态绑定相比,仅仅多出几个内存引用操作,访问栈上的调用者,读取调用者的动态类型,读取该类型的方法表,读取方法表中某个索引值对应的目标方法。

但是即时编译还拥有两种性能更好的优化手段:内联缓存和方法内联。

内联缓存:

     内联缓存是一种加快动态绑定的优化技术。他能够缓存虚方法调用中调用者的动态类型,以及该类型所对应的目标方法。之后的执行过程中,如果碰到已缓存的类型,内联缓存变回直接调用该类型所对应的目标方法,如果没有碰到已缓存的类型,内联缓存则退化到使用基于方法表的动态绑定。

 

这部分资料看的脑壳疼,看了好多遍算是理顺了。。。    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值