java:方法的虚分派(virtual dispatch)和方法表(method table)

Java方法调用的虚分派

虚分配(Virtual Dispatch)

首先从字节码中对方法的调用说起。Java的bytecode中方法的调用实现分为四种指令:

invokevirtual为最常见的情况,包含virtual dispatch机制;

invokerspecial是作为对private和构造方法的调用,绕过了virtual dispatch;

invokeinterface的实现跟invokevirtual类似;

invokestatic是对静态方法的调用;

其中最复杂的要属invokevirtual指令,它涉及到了多态的特性,使用virtual dispatch做方法调用。

virtual dispatch机制会首先从receiver(被调用方法的对象)的类的实现中查找对应的方法,如果没找到,则去父类查找,直找到函数并实现调用,而不是依赖于引用的类型。

下面是一段有趣的代码。反映了virtual dispatch机制和一般的field访问的不同。

运行结果:

前两行输出中,对于Intro这个属性的访问,直接指向了父类中的变量,因为引用类型为父类。

第二行对于target()的方法调用,则是指向了子类中的方法,虽然引用类型也为父类,但这是虚分配的结果,虚分配不管引用类型的,只查被调用对象的类型·。

既然需分派机制是从被调用对象本身的类开始查找,那么对于一个覆盖了父类中某方法的子类的对象,是无法调用父类中那个被覆盖的方法的吗?

在虚分派机制中这确实是不可以的。但却可以通过invokespecial实现。如下代码:

func()就成功地调用了父类的方法target(),虽然target()已经被子类重写了。具体的调用细节,从字节码中可以看到:

其中使用了invokespecial指令,而不是施行需分派策略的invokevirtual指令。

方法表(Method Table)

介绍了虚分派,接下来介绍是它的一种实现方法—方法表。类似于C++虚函数表vtbl。

在有的JVM实现中,使用了方法表机制实现虚分派,而有时候,为了节省内存可能不采用方法表的实现。

不要被方法表这个名字迷惑,它并不是记录所有方法的表。它是为虚分派服务,不会记录用invokestatic调用的静态方法和用invokespecial调用的够着函数和私有方法。

JVM会在链接类的过程中,给类分配相应的方法表内存空间。每个类对应一个方法表。这些都是存在于method area区中的。这里与C++略有不同,C++中每个对象的第一个指针就是指向了相应的虚函数表。而Java中每个对象索引到对应的类,在对应的类数据中对应一个方法表。

一种方法表的实现如下:

父类的方法比子类的方法先得到解析,即父类的方法相对于子类的方法位于表的前列。

表中每项对应于一个方法,索引到实际方法的实际代码上。如果子类重写了父类中某个方法的代码,则该方法第一次出现的位置的索引更换到子类的实现代码上,而不会在方法表中出现新的项。

JVM运行时,当代码索引到一个方法时,是根据它在方法表中的偏移量来实现访问。(第一次执行到调用指令时,会执行解释,将符号索引替换为对应的直接索引)。

invokeinterface与invokevirtual的比较

当使用invokeinterface来调用方法时,由于不同的类可以实现同一interface,我们无法确定在某个类中的interface中的方法处在哪个位置。于是,也就无法解释CONSTANT_interfaceMethodref-info为直接索引,而必须每次都执行一次在methodtable中的搜索了。所以,在这种实现中,通过invokeinterface访问方法比通过invokevirtual访问明显慢很多。

java方法的虚分派和方法表的更多相关文章

  1. 通过字节码分析Java方法的静态分派与动态分派机制

    在上一次[https://www.cnblogs.com/webor2006/p/9723289.html]中已经对Java方法的静态分派在字节码中的表现了,也就是方法重载其实是一种静态分派的体现,这 ...

  2. java内省机制及PropertyUtils使用方法

    背景 一般情况下,在Java中你可以通过get方法轻松获取beans中的属性值.但是,当你事先不知道beans的类型或者将要访问或修改的属性名时,该怎么办?Java语言中提供了一些像java.bean ...

  3. Java中的equals和hashCode方法

    本文转载自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要 ...

  4. Java提高篇——equals()与hashCode()方法详解

    java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...

  5. Java中各种(类、方法、属性)访问修饰符与修饰符的说明

    类: 访问修饰符 修饰符 class 类名称 extends 父类名称 implement 接口名称 (访问修饰符与修饰符的位置可以互换) 访问修饰符 名称 说明 备注 public 可以被本项目的所 ...

  6. [原创]java WEB学习笔记79:Hibernate学习之路--- 四种对象的状态,session核心方法:save()方法,persist()方法,get() 和 load() 方法,update()方法,saveOrUpdate() 方法,merge() 方法,delete() 方法,evict(),hibernate 调用存储过程,hibernate 与 触发器协同工作

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  7. Java 重写hashCode 方法和equals方法

    package Container; import java.util.HashSet; import java.util.Iterator; /* Set 元素是无序的(存入和取出的顺序不一定一致) ...

  8. java中equals方法和hashcode方法的区别和联系,以及为什么要重写这两个方法,不重写会怎样

    一.在Object类中的定义为:public native int hashCode();是一个本地方法,返回的对象的地址值.但是,同样的思路,在String等封装类中对此方法进行了重写.方法调用得到 ...

  9. Java中的equals和hashCode方法详解

    Java中的equals和hashCode方法详解  转自 https://www.cnblogs.com/crazylqy/category/655181.html 参考:http://blog.c ...

随机推荐

  1. 揭秘Node.js深受欢迎的原因

    揭秘Node.js深受欢迎的原因 http://www.php100.com/html/dujia/2014/1127/7922.html

  2. J20180116

    用度 总务 用度係 总务科(管理办公用品等) 型紙 设计图 プラント 工厂

  3. noip2016 小结(ac两题+学习总结)

    NOIP2016考试小结 DAY 1 T1 题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业. 有一天, 这些玩具小人把小南的眼镜藏了起来. 小南发现玩具小人们围成了一个圈,它们有的面朝圈内, ...

  4. Java经典算法之折半查找(二分法)

    采用二分法时,数据应是有序并且不重复的 与小时候玩的猜数游戏是一样的,会让你猜一个他所想的1~100之间的数,当你猜了一个数后,他会告诉你三种选择中的一个,比他想的大,或小,或猜中了,为了能用最少的次 ...

  5. linux centos7安装mysql

    1.下载并安装官方的 yum repository (新建了mysql文件夹) wget -i -c http://dev.mysql.com/get/mysql57-community-releas ...

  6. Window对象与DOM

    目前,前端插件数不胜数,比如有移动端滑动特效插件Swiper,下拉刷新的iScroll,弹出框插件layer,还有我们经常使用的JQuery,jquery.mobile等,这些插件能够满足我们日常的基 ...

  7. 转:python中使用txt文本保存和读取变量

    问题: 在python中需要经常有需要提前生成复杂的计算结果变量的需求减少程序计算运行时间的需求,因此这里把变量存在txt文本文件中. 解决方法: 使用两个函数解决问题,一个函数把变量保存到文本文件中 ...

  8. Mysql动态查询

    if条件查询 格式: <if test=”条件判断”> 添加到sql的语句 </if> where标签 简化SQL语句中WHERE条件判断 智能处理and和or 如果使用几个i ...

  9. Android 新闻app的顶部导航栏,怎么实现动态加载?

    TabLayout + viewpager 其中viewpager的适配器要继承FragmentPagerAdapter,要实现动态更新,最主要的是适配器的写法,要在数据发生变化之后清除Fragmen ...

  10. XAMPP--Apache服务无法启动问题定位及处理

    一.问题简述: XAMPP 在使用一段时间后,Apache服务无法启动. 二.详细描述: 安装Xampp服务器套件之后,部署使用正常.一段时间未使用,再次打开时,Apache服务无法启动.错误提示如下 ...