精华内容
下载资源
问答
  • JVM学习笔记第16天-虚方法表
    2020-07-13 15:39:00
    • 在面向对象的编程中,会频繁的使用动态分派,如果在每次的动态分派的过程中都要重新在类的方法元数据中搜索合适的目标的话,可能影响到执行效率。因此,为了提高性能,JVM采用在类的方法区建立一个虚方法表(virtual method table)(非虚方法不会出现在表中)来实现。使用索引表来代替查找。
    • 每个类中都有一个虚方法表,表中存着各个方法的实际入口。
    • 虚方法表什么时候创建?

            虚方法表会在类加载的链接阶段被创建并开始初始化,类的变量初始值准备完成之后,JVM会把该类的方法表也初始化完毕。

    更多相关内容
  • 如果子类继承了父类,但是某个父类的方法没有被子类重写,那么在子类的方法表里边该方法指向的是父类的方法的入口,子类并不会重新生成一个方法,然后让方法表去指向这个生成的,这样做是没有意义的。还有一点,如果...

    编写代码:

    public class MyTest7 {
        public static void main(String[] args) {
            Animal animal = new Animal();
            Animal dog = new Dog();
    
            animal.test("hello");
            dog.test(new Date());
        }
    
    }
    
    class Animal{
        public void test(String str){
            System.out.println("animal str");
        }
    
        public void test(Date date){
            System.out.println("animal date");
        }
    }
    
    class Dog extends Animal{
        @Override
        public void test(Date date) {
            System.out.println("dog date");
        }
    
        @Override
        public void test(String str) {
            System.out.println("dog str");
        }
    }

    运行结果:

    animal str
    dog date

    方法表:
    针对方法调用动态分派的过程,虚拟机会在类的方法区建立一个虚拟方法表的数据结构(virtual method table,vtable),
    针对于invokeinterface指令来说,虚拟机会建立一个叫做接口方法表的数据结构(interface method table,itable)

    方法表会在类的连接阶段初始化,方法表存储的是该类方法入口的一个映射,比如父类的方法A的索引号是1,方法B的索引号是2。。。
    如果子类继承了父类,但是某个父类的方法没有被子类重写,那么在子类的方法表里边该方法指向的是父类的方法的入口,子类并不会重新生成一个方法,然后让方法表去指向这个生成的,这样做是没有意义的。还有一点,如果子类重写了父类的方法,那么子类这个被重写的方法的索引和父类的该方法的索引是一致。比如父类
    A的test方法被子类C重写了,那么子类C的test方法的索引和父类A的test方法的索引都是1(打个比方),这样做的目的是为了快速查找,比如说在子类里边找不到一个方法索引为1的方法,那么jvm会直接去父类查找方法索引为1的方法,不需要重新在父类里边遍历。

    展开全文
  • 啊!Java虚方法

    2021-03-09 22:52:25
    什么是Java的虚方法呢,我们首先看看什么是虚函数虚函数百度百科的解释为:在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的[成员函数],用法格式为:virtual 函数返回类型 函数名(参数) {[函数体]}...

    什么是Java的虚方法呢,我们首先看看什么是虚函数

    虚函数

    百度百科的解释为:

    在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的[成员函数],用法格式为:virtual 函数返回类型 函数名(参数表) {[函数体]};实现[多态性],通过指向派生类的基类[指针]或引用,访问派生类中同名覆盖成员函数。

    从上面解释上我们抓住几个关于虚函数的关键字 基类、派生类、同名覆盖(重写),因此我们可以理解为虚函数其实就是描述我们子类重写的父类方法。

    在虚函数声明定义这块,C++可以通过virtual关键字来进行直接声明,而在Java中,并没有提供我们关键字来声明虚函数,但是我们通过虚函数的定义,我们可以理解为被override的方法都是virtual的。

    关于虚方法的调用

    在Java语言中,class文件被会解释成机器码,而方法调用会被解释成具体的方法调用指令,大致可以以下五类指令:

    指令

    描述

    invokestatic

    调用静态方法

    invokespecial

    调用实例构造方法,私有方法和父类方法

    invokevirtual

    调用虚方法

    invokeinterface

    调用接口方法,在运行时再确定一个实现此接口的对象

    invokedynamic

    在运行时动态解析出调用点限定符所引用的方法之后,调用该方法;

    注意:invokedynamic 指令是jdk1.7才加入的,但是在jdk1.7中并没有开始使用。在jdk1.8中才开始大量使用,主要就是我们大量用的 lambda 表达式。

    我们接下来去字节码验证下invokevirtual指令,so! 我们来举个🌰

    // 类声明文件如下:

    public class VirtualDemo {

    public static void main(String[] args) {

    Parent obj = new Child();

    obj.func();

    }

    }

    class Parent{

    public void func(){

    System.out.println("parent func");

    }

    }

    class Child extends Parent{

    @Override

    public void func() {

    System.out.println("child func");

    }

    }

    接下来我们来获取这个类的字节码:

    // dos 命令如下

    javac VirtualDemo.java

    javap -verbose VirtualDemo

    VirtualDemo部分字节码指令如下:

    bf80a8b4044c

    VirtualDemo部分字节码指令.png

    解释:在字节码第4行,我们可以看到是一个invokespecial指令,代表调用的是调用子类Child的实例构造init方法。在第9行中,我们可以看到是一个invokevirtual指令,表示调用虚方法,并且表示这是父类Parent中的方法func(),但这只是编译时是这样表示,等字节码真正执行的时候会通过方法表去正确找到子类Child中func()方法。

    参考链接:

    展开全文
  • 虚方法调用在Java虚拟机中的实现方式?

    万次阅读 多人点赞 2021-05-20 00:27:56
    虚方法调用包括 invokevirtual 指令和 invokeinterface 指令。 如果这两种指令所声明的目标方法被标记为 final,那么 Java 虚拟机会采用静态绑定。否则,Java 虚拟机将采用动态绑定,在运行过程中根据调用者的动态...

    写在前面

    本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

    本专栏目录结构和文献引用请见100个问题搞定Java虚拟机

    解答

    虚方法调用包括 invokevirtual 指令和 invokeinterface 指令。
    如果这两种指令所声明的目标方法被标记为 final,那么 Java 虚拟机会采用静态绑定。否则,Java 虚拟机将采用动态绑定,在运行过程中根据调用者的动态类型,来决定具体的目标方法。
    Java 虚拟机的动态绑定是通过方法表这一数据结构来实现的。
    方法表中每一个重写方法的索引值,与父类方法表中被重写的方法的索引值一致。
    在解析虚方法调用时,Java 虚拟机会纪录下所声明的目标方法的索引值,并且在运行过程中根据这个索引值查找具体的目标方法。
    Java 虚拟机中的即时编译器会使用内联缓存来加速动态绑定。
    

    补充

    虚方法调用

    Java 里所有非私有实例方法调用都会被编译成 invokevirtual 指令,而接口方法调用都会被编译成 invokeinterface 指令。

    这两种指令,均属于 Java 虚拟机中的虚方法调用。

    在绝大多数情况下,Java 虚拟机需要根据调用者的动态类型,来确定虚方法调用的目标方法。这个过程我们称之为动态绑定。

    那么,相对于静态绑定的非虚方法调用来说,虚方法调用更加耗时。

    final虚方法

    在 Java 虚拟机中,静态绑定包括用于调用静态方法的 invokestatic 指令,和用于调用构造器、私有实例方法以及超类非私有实例方法的 invokespecial 指令。

    如果虚方法调用指向一个标记为 final 的方法,那么 Java 虚拟机也可以静态绑定该虚方法调用的目标方法。

    方法表

    Java 虚拟机中采取了一种用空间换取时间的策略来实现动态绑定。它为每个类生成一张方法表,用以快速定位目标方法。

    那么方法表具体是怎样实现的呢?

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

    方法表本质上是一个数组,每个数组元素指向一个当前类及其祖先类中非私有的实例方法。

    这些方法可能是具体的、可执行的方法,也可能是没有相应字节码的抽象方法。

    方法表满足两个特质:

    1. 子类方法表中包含父类方法表中的所有方法;
    2. 子类方法在方法表中的索引值,与它所重写的父类方法的索引值相同。

    方法调用指令中的符号引用会在执行之前解析成实际引用。

    对于静态绑定的方法调用而言,实际引用将指向具体的目标方法。对于动态绑定的方法调用而言,实际引用则是方法表的索引值(实际上并不仅是索引值)。

    在执行过程中,Java 虚拟机将获取调用者的实际类型,并在该实际类型的虚方法表中,根据索引值获得目标方法。这个过程便是动态绑定。

    展开全文
  •  静态的方法是非虚方法(Java中的非虚方法有private,final,static,构造器,非虚方法无需根据具体的对象遍历方法区的方法表,决定调用关系)  也是说,对于静态类型方法的调用,是其声明类型的,如Parent c = ...
  • C++函数解析

    2021-03-03 03:42:59
    关于函数的使用方法,我在这里不做过多的阐述。大家可以看看相关的C++的书籍。在这篇文章中,我只想从函数的实现机制上面为大家一个清晰的剖析。当然,相同的文章在网上也出现过一些了,但我总感觉这些文章不是...
  • 实验五 C++虚方法表机制 一、实验目的  1.了解面向对象语言的单一继承的翻译 2.加深对面象对象语言中的继承和多态机制的理解 3.理解C++的虚方法表 二、实验说明 本实验通过对C++虚函数表机制的分析和模拟,进一步...
  • java多态的实现是通过itable(interface method table:接口方法表), vtable(virtual method table:虚方法表)来实现方法的准确跳转。 接口方法表和虚方法表的原理和C++的虚函数表类似。 C++的虚函数和纯函数的...
  • 函数详解

    万次阅读 多人点赞 2018-06-22 17:29:10
    本文转自:...这个技术的核心是函数(下文简称虚表)。本文介绍函数是如何实现动态绑定的。二、类的虚表每个包含了函数的类都包含一个虚表。我们知道,当一个类(A)继承另一个类(B)时...
  • C++函数详解

    千次阅读 多人点赞 2019-01-05 09:51:57
    C++的函数(Virtual Function)是通过一张函数(Virtual Table)来实现的。简称为V-Table。在这个中,主要是一个类的函数的地址,这张表解决了继承、覆盖(override)的问题,保证其能真实的反应实际的函数。...
  • 文章目录一、函数二、首先讲一下结论:三、证明 一、函数 函数是一块连续的内存,每个内存单元中记录一个JMP指令的地址。 二、首先讲一下结论: 首先,函数在编译时候就已经确定; 对象在构造前...
  • 编译器会构建一张虚表( vtable ),每一个类都有自己独特的虚表。同时,在这个继承链上,编译器会为基类插入一个隐式的指针(一般是对象的首地址),指向虚表,称为__vptr。然后,子类继承父类时,会获得继承下来的_...
  • 虚方法实现多态

    千次阅读 2016-05-26 20:56:15
    大家都知道面向对象的三大特征,...这里的“相同”打上双引号是因为这里的相同的方法仅仅是看上去相同的方法,实际上它们调用的方法是不同的。 ——里氏转换多态是基于对象继承和里氏转换的,那么什么叫叫作里氏转换呢
  • 关于函数的使用方法,我在这里不做过多的阐述。大家可以看看相关的C++的书籍。在这篇文章中,我只想从函数的实现机制上面为大家 一个清晰的剖析。 当然,相同的文章在网上也出现过一些了,但我总感觉这些文章...
  • java:方法的分派(virtual dispatch)和方法表(method table) Java方法调用的分派 分配(Virtual Dispatch) 首先从字节码中对方法的调用说起。Java的bytecode中方法的调用实现分为四种指令: ...
  • 我们首先知道,不同的类具有不同的函数,但是如果针对一个类如果实例化多个对象,那么这些对象的函数是共用的吗?首先如果自己去设计内存占用时,从节省内存的角度去考虑的话,我觉得这些实例化后的类应该是...
  • #include using namespace std;/* 每个类都有一张虚方法表,当基类为虚方法,而派生类重载了虚方法,* 则虚方法表中的基类方法被派生类替换*/class AClass{ public: AClass(){ cout } virtual ~
  • 函数工作原理 C++中的函数的作用主要是实现了多态的机制关于多态简而言之就是用父类型别的指针指向其子类的实例然后通过父类的指针调用实际子类的成员函数这种技术可以让父类的指针有多种形态这是一种泛型技术...
  • OC的方法都是虚方法--- 虚函数

    千次阅读 2013-10-13 18:18:56
    1、 父类的指针可以指向子类的对象。 但是调用方法时调用的子类的方法。 2。调用方法不看指针,看对象。 (好处:不同事物被相同事件触发,产生不同的结果) 3。
  • 函数结构

    千次阅读 多人点赞 2019-07-15 18:45:41
    函数 所谓函数就是存放着当前类中所有函数地址的。在实例化一个具有函数的类时,这个也被分配到这个实例对象的内存中,通过函数可以指明所要调用的函数的位置。在C++编译器中函数的地址...
  • 多态(二、函数)

    千次阅读 2022-02-07 20:46:06
    函数的数据储存在属于自己的函数,通过函数指针指向。在类被继承的时候,函数内的数据也会别继承,但是函数不会被继承。 #include <iostream> #include <string> using namespace std...
  • C#中虚方法(virtual)详解

    万次阅读 2020-06-17 22:47:36
    虚方法如何定义? 虚方法怎么声明? 虚方法的规则是什么? 虚方法如何进行调用? 虚方法的作用是什么? 虚方法有什么好处? 虚方法使用时注意什么?
  • 简述函数

    千次阅读 2019-04-04 18:00:28
    据百度百科描述,C++并未规定用何种方法实现函数,但是大部分编译器厂商都选择使用函数这种方法,那到底什么是函数??? 函数,称为V-Table。函数是一片连续的内存区域,每个内存单元存放着...
  • 函数存储位置

    千次阅读 2019-06-17 13:59:30
    函数放在哪里? 2007年01月28日 14:09:00 houdy 阅读数 15329 ...
  • 所有的函数都必须有定义,因为编译器直到运行前也不知道到底要调用哪个版本的函数。 只有通过指针或引用调用函数才会发生动态绑定,因为只有这种情况,引用或指针的静态类型与对象本身的动态类型才会不同。
  • C++虚表结构详解

    千次阅读 2018-12-14 00:06:03
    为了实现虚函数,C++使用动态绑定方式,称为虚表。 虚表是一个包含函数的查找表,该查找表用于动态绑定方式...,“虚方法表”,“分派表”。 虚表虽然用语言描述有点复杂,实际上非常简单。 首先,每个包含虚...
  • c++中基类函数的布局

    万次阅读 2017-04-30 17:47:44
    对象的每个基类都有一个属于自己的函数指针(vfptr)指向函数(vftbl)的某一项,都有一个属于自己的基类指针(vbptr)指向基类(vbtbl)的某一项。 3. 函数中按照对象继承的顺序排列对象的函数...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 133,511
精华内容 53,404
关键字:

虚方法表