`
lilisalo
  • 浏览: 1111492 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多


Virtual Dispatch

首先从字节码中对方法的调用说起。

java的bytecode中对方法的调用实现分为四种情况:

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

2.invokespecial是作为private和构造方法的调用,绕过了virtual dispatch;

3.invokeinterface的实现跟invokevirtual类似。

4.invokestatic是对静态方法的调用。


其中最复杂的要属invokevirtual.

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

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



运行的结果为


其中的第二行是亮点。

对于intro这个filed的访问,直接指向了父类中的变量,因为引用类型为父类。

而对于target的方法调用,则是指向了子类中的方法,虽然引用类型也为父类,但这是virtual dispatch的结果,virtual dispatch不管引用类型的,只查receiver的类型。


既然 虚分派 机制是从receiver对象的子类开始查找,由此看来,对于一个覆盖了父类中某方法的子类的对象,是无法调用父类中那个被覆盖的方法的吗?

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


func()就成功的调用了父类的方法target,虽然target已经被子类重写了。怎么实现的?让我们看一看func方法中生成的字节码:

原来如此,它是通过invokespecial 指令来调用的。


Method Table

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

在有的JVM实现中,使用了方法表(method table)机制实现虚分派(virtual dispatch)。(有时候,为了节省内存而不采用method table实现)

不要被method table这个名字迷惑,它显然不是记录所有method的表。它是为virtual dispatch服务,所以,排除了用invokestatic调用的静态方法和用invokespecial调用的构造函数和私有方法。

JVM会在链接类的过程中,给类分配相应的method table内存空间。每个类对应一个方法表。这些都是存在于method area区中的。这里与C++略有不同,C++中每个对象的第一个指针就是指向了相应的虚函数表。而java中每个对象索引到对应的类,在对应的类数据中对应一个方法表。(关于链接的详细信息,参见博文《java类的装载(Loading)、链接(Linking)和初始化(Initialization)》)


根据《Inside the Java2 Virtual Machine》中所描述,一种方法表的实现如下:

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

JVM运行时,当代码索引到一个方法时,是根据它在方法表中的偏移量来实现访问的。(第一次执行到调用指令时,会将符号索引替换为对应的直接索引,执行解析)。由于invokevirtual调用的方法,在对应的类的method table中都有固定的位置,直接索引的值可以用偏移量来表示。(符号索引解析的最终目的是完成直接索引:对象方法和对象变量的调用都是用偏移量来表示直接索引的)

当使用invokeinterface来调用方法时,则没有那么幸运了。由于不同的类可以实现同一interface,我们无法确定在某个类中的inteface中的方法处在哪个位置。于是,也就无法解析 CONSTANT_intefaceMethodref-info为直接索引,而必须每次都执行一次在methodtable中的搜索了!

所以,在这种实现中通过 invokeinterface访问方法比通过invokevirtual访问明显慢!


分享到:
评论

相关推荐

    Java模拟双分派DoubleDispatch

    分派/dispatch是指如何给一个消息绑定其方法体。Java、C#等仅仅支持单分派(singledispatch)而不支持双分派(double dispatch)。【相关概念,参考《设计模式.5.11访问者模式》p223】对于消息a.foo(b),假设有父类X...

    java head space.txt

    以下的问题是由于java的堆内存已满,需要java运行时加大java的堆内存空间 2019-10-09 18:02:32.858 [http-nio-8239-exec-6] ERROR c.a.b.c.exceptionHandler.CodeBaseExceptionHandler:69 - Handler dispatch failed...

    swing-worker-1.1.jar

    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) at java.awt.EventQueue.dispatchEvent(EventQueue.java:633) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatch...

    dynamicDispatch:java虚拟机的动态分派的例子程序的说明

    dynamicDispatch java虚拟机的动态分派的例子程序的说明

    Log-Dispatch-2.26.tar.gz

    MHA安装依赖包

    bcprov加密库

    Caused by: java.util.jar.JarException: file:/opt/code/signal-Server-master/target/TextSecureServer-1.87.jar has unsigned entries - org/whispersystems/dispatch/DispatchManager$4.class at javax.crypto....

    java操作word:jacob(方法解析+环境配置)

    jacob jacob配置 java操作word java操作word:jacob(方法解析+环境配置)

    C++虚表,你搞懂了吗?

    虚表是一种利用程序语言实现的dynamic dispatch机制,或者说runtime method binding机制,也是我们说的多态。  注:笔者在本文使用C++语言,并且统一用vTable来表示虚表。  虚函数  用virtual关键字修饰的函数...

    ExtJS Jetty启动报错 tag

    org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:35 7) at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:16 9) at org.apache.jasper.compiler....

    dispatch_barrier_(a)sync

    异步和同步的栅栏函数都有以下特点: 1、通过dispatch_barrier_(a)sync添加的block会等待前边所有的block执行完(不包括回调)才执行。 2、在其后添加的block会在dispatch_barrier_(a)sync添加的block执行完之后...

    java代码-Dispatch

    java代码-Dispatch

    CancelBlocks:延迟后分派块的功能集,并具有取消它们的能力。 写在斯威夫特

    延迟后分派块的功能集,并具有取消它们的能力。 用Swift编写。 使用dispatch_block_t而不是本机的dispatch_after并将执行的块保存为dispatch_cancelable_block_t类型,此后,您可以安全地使用它通过使用dispatch_...

    DISPATCH

    DISPATCH

    jamume:Java 多方法

    Java 的多重动态分派 这为 Java 实现了多个动态调度。 它不是一种新的编程语言,而是构造代理,然后将方法分派到实现类中最具体的方法。 它旨在执行 java 编译器在从多个重载方法中进行选择时所做的事情,仅在运行时...

    jacob资源包附有异常解决方法

    Jacob 是Java-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁。使用Jacob自带的DLL动态链接库,并通过JNI的方式实现了在Java平台上对COM程序的调用

    Dispatch IDS for IExplorer Dispatch Events

    Dispatch IDS for IExplorer Dispatch Events

    Connectify Dispatch Hotspot Pro

    注册汉化方法: 双击“Installer”安装...复制Crack目录中的dispatch.dll和web文件夹到软件安装目录中的\plugins\dispatch目录覆盖同名文件。 复制Crack目录中的connectify.exe文件到安装程序目录覆盖同名文件。

    call-dispatch-macro:[WIP]在Rust过程宏中生成函数调用分派器

    :construction: 工作在进行中 :construction:用法use call_dispatch_macro :: call_dispatch;// Define a struct.struct Syscall ;// Put `call_dispatch` attribute on the impl block.#[call_dispatch]impl ...

Global site tag (gtag.js) - Google Analytics