zoukankan      html  css  js  c++  java
  • java方法的虚分派和方法表

    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访问明显慢很多。

  • 相关阅读:
    面试题3
    面试题2
    (原)python爬虫入门(2)---排序爬取的辽宁科技大学热点新闻
    (原)python爬虫入门(1)---爬取辽宁科技大学相关新闻
    Classic Abstract Data Types--C
    面试题1
    (原)----2叉查找树 in C
    《 Trees and Graphs》----CCI_Q4.6
    EasyUI 弹出window子页面,选中某条数据回调给父页面并关闭子页面
    跨域问题解决
  • 原文地址:https://www.cnblogs.com/kexinxin/p/10147209.html
Copyright © 2011-2022 走看看