打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Java运行期间动态确定调用方法的本质

Java为什么能运行期间动态确定调用方法?是怎么实现的呢。

在继承关系中,运行时动态确定要调用的方法的版本,是根据字节码指令invokevirtual来完成的。需要从这个指令的"多态查找"过程说起。

invokevirtual的运行过程如下:

第一、找到操作数栈顶元素的实际类型,记做C,

第二、如果在才、C中找到与常量中描述符和简单名称都相同的方法,则进行权限校验,如果通过,则返回这个方法的直接引用,查找过程结束。权限校验不通过则返回java的illegalaccesserror。

第三、如果经过第二步没找到也没抛出异常,则按照继承关系在父类中查找。

第四、如果始终没有找到,则跑出abstractmethoderror。

由于invokevirtual指令在执行的第一步就是确定接收者的实际类型,所以调用的时候,针对不同的调用者(即所说的方法接收者)会把常量池中的类方法解析到不同的直接引用上,这个过程就是java语言“覆盖”父类方法的本质,也就是“重写”的本质。

  1. 父类 a=new 子类1  
  2. 父类 b=new 子类2  
  3. a.test();  
  4. b.test();  

上面代码a和b分别会调用两个子类的test函数,可以作为例子参考。

-------------------------------------------------------------------------------------------------------

上面的全部都是在说子类重写父类的方法,那么如果在同一个类中重载一个函数,那么是怎么确定调用版本的呢?

这需要从“静态类型”和“动态类型”说起。

比如:

父类 a=new 子类,

在上面,父类是静态类型,子类是动态类型,【因为子类是这个对象的实际类型,称之为动态类型】

如果在一个类

  1. class TR {  
  2.     void test(父类 a) {  
  3.         System.out.print("father");  
  4.     }  
  5.   
  6.     void test(子类1 a) {  
  7.         System.out.print("child 1");  
  8.     }  
  9.   
  10.     void test(子类2 a) {  
  11.         System.out.print("child 2");  
  12.     }  
  13. }  

代码如上。调用的时候,如果这么调用:

父类 a=new 父类

父类 b=new 子类1

父类 c=new 子类2

new TR().test(a);

new TR().test(b);

new TR().test(c);

那么这三句话会分别输出什么呢?

这个有可能会有人回答错误。

会输出三个father!

这是因为,虚拟机(准确的说是编译器)在重载时候是通过静态类型而不是动态类型来确定调用方法的版本的。所以三个调用语句都会选择void test(父类 a)作为调用函数。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Java重载与重写的区别
虚函数与纯虚函数(C++与Java虚函数的区别)的深入分析
Java方法重写的原则是什么?Java开发学习
Java向上转型和向下转型
java基础:编译时和运行时的区别
java多态、动态绑定与静态绑定、向上转型、传值引用和传引引用
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服