-
2019-04-09 14:23:23
1 问题
在C++中,运行时多态是通过虚函数来实现的。本文将讨论关于虚函数实现多态的问题:
- 相信大家都知道怎么使用虚函数实现多态,但是它的原理是什么呢?
- 构造函数可以声明为虚函数吗?为什么?
- 析构函数可以声明为虚函数吗?为什么?
2 概念
2.1 虚表和虚表指针
要理解虚函数实现多态的原理,我们首先要知道 虚表 和 虚表指针 的概念:
- 含有虚成员函数的类称为虚类,如果一个类是虚类,那么编译器会自动为其添加一个虚表(虚函数表)和一个称为虚表指针(指向虚表的的指针,__vptr)的数据成员;
虚表
- 每个虚类,都有一个虚函数表;
- 本质上是一个指针数组,其中元素为指向该类的虚成员函数的函数指针;
- 属于类,为该类的所有对象所共用;(static?)
- 在编译阶段就已经被确定了。(const?)
虚表指针
- 属于对象,是编译器自动添加的一个指针成员变量;
- 虚表指针,在构造函数中初始化;
2.2 虚函数调用过程
现有基类对象指针p和基类虚函数func1
class Base { public: ... virtual void func1() { ... } ... }; int main() { Base* p = new Base(); p->func1(); return 0; }
在执行 “p->func1();” 时,主要步骤有:
- 首先发现 p 是一个指针,且调用的函数 func1 是一个虚函数;
- 此时会通过该对象的虚表指针 __ptr 访问到它的虚表,然后在虚表中查找虚函数func1所对应的函数指针;
- 根据函数指针找到函数func1,并执行。
3 虚函数实现多态原理
现假设已有 Base 和 Derived 两个类,具体情况如下:
#include <iostream> using namespace std; class Base { public: virtual void func1() { cout << "Base func1 called." << endl; } virtual void func2() { cout << "Base func2 called." << endl; } void func3() { cout << "Base func3 called." << endl; } private: int x; int y; }; class Derived : public Base { public: virtual void func1() { cout << "Derived func1 called." << endl; } virtual void func2() { cout << "Derived func2 called." << endl; } virtual void func4() { cout << "Derived func4 called." << endl; } private: int z; };
基类Base具有三个成员函数,其中func1和func2为虚函数,func3为普通成员函数;派生类Derived对func1和func2进行了重写,并新添加了一个虚函数func4。以下为多态的示例代码:
Base* ptrBase = new Derived(); ptrBase ->func1(); //显然输出:Derived func1 called. ptrBase ->func2(); //显然输出:Derived func2 called. ptrBase ->func3(); //显然输出:Base func3 called. ptrBase ->func4(); //报错
分析如下
- 基类Base和派生类Derived都具有虚函数,均为虚类,因此都具有虚表和虚表指针。Base类的虚表vTableBase包含两个函数指针,第一个指向func1,第二个指向func2;Derived类的虚表vTableDerived包含三个函数指针,第一个指向func1,第二个指向func2,第三个指向func4。
- 首先,“new Derived();” 会调用构造函数,生成一个Derived类对象的指针(ptrDerived),并使该对象的虚表指针指向Derived类的虚表;然后,使用ptrDerived对ptrBase的数据成员(当然也包括虚表指针 __ptr )进行初始化,使得ptrBase的虚表指针不再指向Base类的虚表,而是指向Derived类的虚表(实际上是Derived类虚表的子集,由于func4,不是Base的成员函数,所以该虚表中不会包含有func4的函数指针)即:此时 ptrBase所指对象的虚表依然包含2个函数指针,不过它们不再指向基类Base的成员函数func1 和 func2,而是指向派生类Derived的成员函数 func1 和 func2。
- 结合虚函数的调用过程:首先,ptrBase 是一个对象指针,且 func1 是一个虚函数,然后根据该对象的虚表指针 __vptr,找到其所指的虚表,接着找到虚函数 func1 的函数指针,并对其执行。由于此时虚表中虚函数 func1 的函数指针指向派生类Derived的虚函数 func1 ,所以,执行的是派生类的虚函数 func1。
4 构造函数可以声明为虚函数吗?
显然构造函数是不能声明为虚函数的。
我们知道,在调用虚函数前,需要先访问虚表指针,得到虚表,然后再执行虚表中相对应的函数。假设,现在将构造函数声明为虚函数:调用构造函数时,发现构造函数是一个虚函数,然后去访问虚表指针,可是虚表指针是在构造函数中进行初始化的,而目前构造并没有执行,也就是说,虚表指针还没有初始化,只是一个空值,理所当然的,也就找不到指向构造函数的函数指针,因此无法完成构造函数的调用。可见,构造函数是不能声明为虚函数的。5 析构函数可以声明为虚函数吗?
1、当然是可以的,而且,为了防止内存泄漏,基类的析构函数必须声明为虚函数!
2、为什么将基类析构函数声明为虚函数,就可以防止内存泄漏?- 如果没有将基类析构函数声明为虚函数,在释放指向派生类对象的基类指针的时候,只会调用基类的析构函数,而派生类的析构函数不会被调用,导致属于派生类的新添加的数据得不到释放,从而导致内存泄漏。
- 如果将析构函数声明为虚函数,在释放指向派生类对象的基类指针的时候,会调用派生类的析构函数,而派生类的析构函数会自动调用基类的析构函数,从而释放所有内存,避免了内存泄漏。
3、可是,有个问题,为什么将基类析构函数声明为虚函数之后,在释放指向派生类对象的基类指针时,调用的是派生类的析构函数?难道派生类的析构函数重写了基类的析构函数?不可能啊,基类析构函数和派生类析构函数的函数名不同,不能构成重写啊。
- 其实,析构函数是一个特殊的函数,编译器在编译时,析构函数的名字统一为destucter;
- 所以只要将基类的析构函数声明为虚函数,不管子类的析构函数前是否加virtual,都构成重写。这也就可以解释为什么将基类析构函数声明为虚函数,释放指向派生类对象的基类指针时,会调用派生类的析构函数,因为虚表中的函数指针指向的是派生类的析构函数。
6 参考文献
https://blog.csdn.net/lihao21/article/details/50688337(推荐,讲得很好)
https://blog.csdn.net/han8040laixin/article/details/81704165更多相关内容 -
Java多态原理
2021-03-28 15:08:51Java多态原理 最近在准备面试,顺便复习以下Java最基础的东西 仅作参考 Java多态原理Java多态原理0. 什么是多态1. jvm内部类信息2. 多态的实现原理 为了更好地理解多态的原理,首先必须对jvm内存模型、Java方法调用...Java多态原理
最近在准备面试,顺便复习以下Java最基础的东西
仅作参考
为了更好地理解多态的原理,首先必须对jvm内存模型、Java方法调用等知识有点了解。
0. 什么是多态
多态分为两种,本文着重讲解运行时多态。
- 编译时多态。也叫做静态多态,指的是方法的重载,在同一个类中,同样的方法签名却有不同的参数。编译时通过静态绑定就能实现。
- 运行时多态。也叫做动态多态,指的是方法的重写,在具有继承关系的类中,子类重写了父类方法,方法签名和参数都一致,父类引用指向子类实例,该引用调用被重写方法时实际上调用的是子类的方法。需要运行时进行动态绑定实现。
1. jvm内部类信息
在下图可以看到jvm关于方法区中的类信息。
jvm通过类加载器,把类加载进方法区,在方法区维护了类的基本信息,其中就包括了方法信息,而为了能够快速访问具体方法,每个类都有一个方法表,里面存放了指向对应方法的指针。当需要调用某个类的方法时,只需要找到相应偏移量,就能够快速地找到对应的方法。
方法表的构成:
某个类的方法表包含了Object类、祖先类、父类、自身的方法指针。
2. 多态的实现原理
举个例子 A b = new B();,A B是具有继承关系的。示例代码如下:
public class A{ //对比方法 public void method1(){ ...; } //被子类重写的方法 public void method2(){ ...; } }
public class B extend A{ //对比方法 public void method3(){ ...; } //重写了父类的方法 @Override public void method1(){ ...; } }
在方法表里是如何的呢?
看下图:
可以看到,重写就是把子类方法的指针替换了方法表里父类对应方法项的值!
那么,具体的调用过程是怎样的呢?
A b = new B(); b.method2();
注意:此处笔者没有深入研究方法调用过程,仅作参考!欢迎同学们在评论区指正23333
首先,通过变量类型A,找到A的类信息,确定A的method方法的偏移量。然后,通过对象引用,找到堆中B对象,通过B对象,找到B类信息,根据偏移量,调用B类方法表对应的方法!
最终实现了多态!
-
Python类继承和多态原理解析
2020-12-20 17:01:27这篇文章主要介绍了python类继承和多态原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 现在属于是老年人的脑子,东西写着写着就忘了,东西记着记着就... -
Python面向对象之多态原理与用法案例分析
2020-12-23 11:49:58本文实例讲述了Python面向对象之多态原理与用法。分享给大家供大家参考,具体如下: 目标 多态 面向对象三大特性 封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中 定义类的准则 继承 实现代码的重用,相同... -
多态原理
2020-04-28 00:36:37多态调用原理 本文为「熊二不二」的文章节选 原文链接附于文底 class Base { public: virtual void Funtest1(int i) { cout << "Base::Funtest1()" << endl; } virtual void Funtest2(int i) { ....多态调用原理
本文为「熊二不二」的文章节选
原文链接附于文底class Base { public: virtual void Funtest1(int i) { cout << "Base::Funtest1()" << endl; } virtual void Funtest2(int i) { cout << "Base::Funtest2()" << endl; } int _data; }; int main() { cout << sizeof(Base) << endl; Base b; b._data = 10; return 0; }
8?不知道大家有没有问题,反正我是有疑惑了。以前在对象模型(https://blog.csdn.net/qq_39412582/article/details/80808754)时我提到过怎么来求一个类的大小。按照那个方法,这里应该是4才对啊,为什么会是8呢?
通过观察。我们发现这个例子里面和以前不一样,类成员函数变成了虚函数,这是不是引起类大小变化的原因呢?
我们假设就是这样,然后看看内存里是怎么存储的呢?
可以看到它在内存里多了四个字节,那这四个字节的内容到底是什么呢?
是不是有点看不懂,我们假设它是一个地址去看地址里存的东西的时候发现它存的是两个地址。
我假设它是虚函数的地址,我们来验证一下:typedef void (__stdcall *PVFT)(); //函数指针 int main() { cout << sizeof(Base) << endl; Base b; b._data = 10; PVFT* pVFT = (PVFT*)(*((int*)&b)); while (*pVFT) { (*pVFT)(); pVFT+=1; } return 0; }
结果好像和我们的猜想一样,是一件开心的事。然后我给一张图总结一下:
对于派生类的东西我给个链接仔细看,人家总结的超级赞,我偷个懒就不写了,老铁们包容下啊。
派生类虚表:
1.先将基类的虚表中的内容拷贝一份
2.如果派生类对基类中的虚函数进行重写,使用派生类的虚函数替换相同偏移量位置的基类虚函数
3.如果派生类中新增加自己的虚函数,按照其在派生类中的声明次序,放在上述虚函数之后
https://coolshell.cn/articles/12176.html多态缺陷
●降低了程序运行效率(多态需要去找虚表的地址)
●空间浪费
————————————————
版权声明:本文为CSDN博主「熊二不二」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39412582/article/details/81628254 -
Python面向对象程序设计之继承、多态原理与用法详解
2020-12-20 08:57:21本文实例讲述了Python面向对象程序设计之继承、多态原理与用法。分享给大家供大家参考,具体如下: 相关内容: 继承:多继承、super、__init__、重写父类变量或函数 多态 继承: 在Python3中,不写基类的类默认... -
Python面向对象之多态原理与用法案例分析_面向对象中多态的概念
2020-11-23 09:25:55Python面面向向对对象象之之多多态态原原理理与与用用法法案案例例分分析析 这篇文章主要介绍了Python面向对象之多态原理与用法,结合具体案例形式分析了Python多态的具体功能原理 使用 法与操作注意事项,需要的朋友... -
java中多态概念、实现原理详解
2020-08-30 20:31:05JAVA中多态性是对象多种表现形式的体现。在面向对象中,最常见的多态发生在使用父类的引用来引用子类的对象。下面这篇文章主要给大家介绍一下,需要的朋友可以参考下 -
从底层汇编理解C++多态原理
2021-03-13 11:24:15这门课的初衷就是让大家能够从汇编的角度看多态实现的背后原理,在理解原理的基础上我们自己动手实践。 在面试(多态是面试题的高频题目)的过程中,能够做到心中自有丘壑。 自己动手模拟多态的原理过程中,去如何... -
深入分析java中的多态原理(jvm角度分析)
2019-07-24 17:10:36对于java中多态概念的理解一直是面试常问的问题,所以今天花了一些时间好好地整理了一下,力求从java虚拟机的角度来分析和理解多态。 一、认识多态 1、方法调用 在Java中,方法调用有两类,动态方法调用与静态方法...对于java中多态概念的理解一直是面试常问的问题,所以今天花了一些时间好好地整理了一下,力求从java虚拟机的角度来分析和理解多态。
一、认识多态
1、方法调用
在Java中,方法调用有两类,动态方法调用与静态方法调用。
(1)静态方法调用是指对于类的静态方法的调用方式,是在编译时刻就已经确定好具体调用方法的情况,是静态绑定的。
(2)动态方法调用需要有方法调用所作用的对象,是在调用的时候才确定具体的调用方法,是动态绑定的。
我们这里所讲的多态就是后者—动态方法调用。
2、多态概念
多态有两种:类内部之间的多态和类之间的多态。我们先看一下标准的概念:
多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定
(1)Java的方法重载(类内部之间的多态):就是在类中可以创建多个方法,它们具有相同的名字,但可具有不同的参数列表、返回值类型。我们举个例子来解释,就是一对夫妇生了多胞胎,多胞胎之间外观相似,其实是不同的孩子。
(2)Java的方法重写(父类与子类之间的多态):子类可继承父类中的方法,但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。重写的参数列表和返回类型均不可修改。我们再举个例子,就是子承父业,但是儿子有自己想法,对父亲得产业进行再投资的过程。
二、代码实现多态
1、类内部之间得多态:方法重载
public class SingleClass { //孩子1: public String child(){ System.out.println("child1"); return "child1"; } //孩子2:与孩子1参数个数不同 public String child(String a){ System.out.println("child2"); return "child2"; } //孩子3:与孩子4参数顺序不同 public String child(int a,String s){ System.out.println("child3"); return "child3"; } //孩子4:与孩子3参数顺序不同 public String child(String s,int a){ System.out.println("child4"); return "child4"; } public static void main(String[] args){ //重载方法调用:略 } }
从上述代码我们可以看到,在类的内部可以有相同的方法名,但是有唯一的参数列表。当然返回类型和修饰符也可以不同。下面我们再看一下类之间的多态。
2、类之间的多态:方法重写
类之间的多态其实是有两种方式:继承和接口。我们对这两种方式一个一个说明。
(1)继承方式实现多态
对于继承方式我们使用一个例子来解释,比如说父亲可以对自己的房子有处理权,儿子继承父业同样也有处理权。
第一步:定义父类
public class Father { public void dealHouse(){ System.out.println("父亲处置房产"); } }
第二步:定义子类(大儿子和小儿子)
//大儿子 public class SonA extends Father { @Override public void dealHouse() { System.out.println("大儿子处置房产"); } } //小儿子 public class SonB extends Father { @Override public void dealHouse() { System.out.println("小儿子处置房产"); } }
第三步:测试
public class Test { public static void main(String[] args) { Father father=new Father(); Father sonA=new SonA(); Father sonB=new SonB(); father.dealHouse(); sonA.dealHouse(); sonB.dealHouse(); } } //父亲处置房产 //大儿子处置房产 //小儿子处置房产
(2)接口方式实现多态
接口方式实现继承方式其实跟上面一样,只不过把父类变成了接口而已,其他内容只有微笑的变化,这里就不演示了,在这里只给出父接口的形式。
public interface Father { public void dealHouse(); }
到了这基本上就对多态形式的代码实现进行了演示,案例也比较简单,但是这对我们理解多态的思想还不够,我们最主要的还是从虚拟机的角度来分析一下。
三、分析多态
想要深入分析多态,我们需要弄清楚几个问题。
1、jvm内存
在上面的代码中我们其实已经看到了,不管是类内部之间实现的多态,还是类之间实现的多态,这些方法的名字其实都是一样的,那我们的程序在运行的时候,底层虚拟机是如何去区分的呢(java虚拟机实现动态调用)?为此我们还是先从java虚拟机讲起。
其实java虚拟机在执行java程序的时候,并不是直接运行的,他需要一个过程,我们使用一张图来看下:
上面这张图已经很清晰,也就是说,我们的java文件要想运行,需要通过java编译器编译成.class文件,然后通过类装载器讲.class文件装载到JVM中,最后才是执行。而且JVM分了五个区域,那么在代码中定义的那些多态方法存到了哪个地方呢?为此我们还需要对这块内存区域进行一个分析:我给出了一张java7的运行时数据区划分图,对于每一个区域的基本情况我相信你也能看明白。那么我们的多态方法到底存在了哪呢?没错就是后一个方法区。java堆存的是就是我们建立的一个个实例对象,而方法区存的就是类的类型信息。
而且这个方法区中的类型信息跟在堆中存放的class对象是不同的。在方法区中,这个class的类型信息只有唯一的实例(所以方法区是各个线程共享的内存区域),而在堆中可以有多个该class对象。也就是说方法区的类型信息就是像一个模板,那些class对象就好比通过这些模板创建的一个个实例。
2、通过例子来分析
现在我们拿上面的例子来说明一下多态在java虚拟机中是如何实现的。在测试类中有两行代码:
Father sonA=new SonA(); Father sonB=new SonB();
当程序运行到Father sonA=new SonA()这里就出现了多态,这是因为编译时看到Father,但是运行时new出来一个SonA类,两种类型还不一样。那么这些代码在运行的时候在内存中是如何保存的呢?
(1)Father sonA是一个引用类型,存在了java栈中的本地方法表中了。
(2)new SonA其实创建了一个实例对象,存储在了java堆中。
(3)SonA的类型数据存在了方法区中
我们在内存中看一下:
reference中存储的就是对象在堆中的实际地址,在堆中存储的对象信息中包含了在方法区中的相应类型数据。流程很简单,我们梳理一下:
第一步:虚拟机通过reference(Father的引用)查询java栈中的本地变量表,得到堆中的对象类型数据的指针,
第二步:通过到对象的指针找到方法区中的对象类型数据
第三步:查询方法表定位到实际类(SonA类)的方法运行。
好了,到第三步我们知道,其实是通过方法表来定位到实际运行的方法的。下面我们再来看看这个方法表是什么。
3、方法表
方法表肯定是存在于方法区中的,它是实现多态的关键所在,这里面保存的就是实例方法的引用,而且是直接引用。java虚拟机在执行程序的时候就是通过这个方法表来确定运行哪一个多态方法的。
我们通过上面的例子,来演示一下父子类在方法表中是如何保存的:
很明显每一个类都会有一个方法表,子类中不同的方法指向不同的类型信息。继承自Object的就指向Object,继承自Father的就指向Father(也就是包含了父类的方法dealHouse)。
可能我们到这就迷糊了,既然子类的dealHouse方法其实是父类Father的,那么为什么会执行子类的dealHouse方法呢?别着急往下看。这是java虚拟机区分多态方法(实现动态调用)的精华所在。
当Son类的方法表会有一个指向Father类dealHouse方法的指针,同时也有一个指向自己dealHouse方法的指针,这时候,新的数据会覆盖原有的数据,也就是说原来指向Father.dealHouse的那个引用会被替换成指向Son.dealHouse的引用(占据原来表中的位置)
注意:
上述讲述的其实是对继承实现的多态的一种分析,对接口实现的,会有着不一样的理解。Java虚拟机 对于接口方法的调用是采用搜索方法表的方式,如,要在Father接口的方法表中找到dealHouse()方法,必须搜索Father的整个方法表。从效率上来说,接口方法的调用总是慢于类方法的调用的。
以上就是对java多态的分析与理解,总结一下就是说,类调用和接口调用两种方式区分不同方法是不一样的,类调用是根据多态方法在方法表中的位移量,而接口调用是根据搜索整个方法表来实现的。
机 对于接口方法的调用是采用搜索方法表的方式,如,要在Father接口的方法表中找到dealHouse()方法,必须搜索Father的整个方法表。从效率上来说,接口方法的调用总是慢于类方法的调用的。
以上就是对java多态的分析与理解,总结一下就是说,类调用和接口调用两种方式区分不同方法是不一样的,类调用是根据多态方法在方法表中的位移量,而接口调用是根据搜索整个方法表来实现的。
欢迎关注微信公众号:java的架构师技术栈。回复关键字获取各种教程资源和新手入门到架构师学习路线。
-
C++之多态原理
2020-04-03 01:42:49首先可以确定的是virtual关键字会传递给C++编译器一个重要信息,那就是这个函数是一个虚函数,需要特殊处理。 C++编译器到底设计了一种什么样的方案来实现的? 编译器的设计者就想了个巧妙的办法,弄一张虚函数表... -
多态原理探究
2019-06-02 21:17:54多态 1、存在继承 2、子类重写父类函数 存在虚函数 3、要有父类指针(引用)指向子类对象 class Parent { public: Parent(int a = 0) { this->a = a; } virtual void Print()//1.动手脚 写virtual... -
c++ 多态原理详解
2022-05-03 15:35:05重写是语法的叫法,覆盖是原理层的叫法。 3.另外Func2继承下来后是虚函数,所以放进了虚表,Func3也继承下来了,但是不是虚函数,所以不会放进虚表。 虚函数表本质是一个存虚函数指针的指针数组,一般情况这个数组最... -
【转】深入理解Java多态原理
2021-03-01 06:14:31之前一直知道多态是什么东西,平时敲代码也经常用到多态,但一直没有真正了解多态底层的运行机制到底是怎么样的,这两天才研究明白点,特地写下来,跟各位同学一起进步,同时也希望各位大神指导和指正。多态的概念:... -
C++中的多态原理探究
2020-04-11 00:22:354、多态案例5、多态的理论基础二、多态原理探究1、多态的实现原理2如何证明vptr指针的存在3、构造函数中能调用虚函数,实现多态吗? 一、多态 1、多态问题抛出 如果子类定义了与父类中原型相同的函数会发生什么? 在... -
多态原理剖析
2019-08-16 22:17:20多态:多种形态,去完成某个行为时,当不同对象取完成时,会产生的不同状态 同一件事情,不同的人去做,得到的过程结果不一样 eg:(1)比如买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是... -
黑马程序员 - 多态原理
2022-04-05 09:55:02多态原理刨析图示: -
深入剖析C++实现多态的原理
2022-04-11 11:17:50文章目录前言有虚函数的类对象模型派生类继承有虚函数的基类的对象模型无虚函数派生类继承有虚函数基类的对象模型有虚函数派生类继承有虚函数的基类对象模型多态原理剖析汇编代码分析多态的过程有关多态的常见几个... -
c++ 多态原理剖析
2019-11-20 11:08:14内容来自: 传智播客 (学习C++基础的朋友,我强烈推荐传智播客的传智扫地僧的课程,真是我迄今为止见过将C++讲的最好的老师...// 多态 class A { public: int a; A(int a) { this->a = a; } virtual void ... -
C++多态原理
2019-05-11 15:53:48C++中多态的实现原理 当类中声明虚函数时,编译器会在类中生成一个虚函数表 虚函数表是一个存储类成员函数指针的数据结构 虚函数表是由编译器自动生成与维护的 virtual成员函数会被编译器放入虚函数表中 存在... -
深入理解JAVA多态原理
2018-10-13 11:28:23之前一直知道多态是什么东西,平时敲代码也经常用到多态,但一直没有真正了解多态底层的运行机制到底是怎么样的,这两天才研究明白点,特地写下来,跟各位同学一起进步,同时也希望各位大神指导和指正。 多态的... -
多态的原理
2022-02-12 10:31:08首先,在了解多态的原理之前,先了解下面的这些概念来帮助理解 方法区:在JVM内存模型中,主要的部分之一,和堆区一样,是线程共享的区域,一般用来存放类信息,常量,静态变量,即时代码编译器编译后的代码 ... -
深入理解Java多态原理
2019-04-03 11:48:22之前一直知道多态是什么东西,平时敲代码也经常用到多态,但一直没有真正了解多态底层的运行机制到底是怎么样的,这两天才研究明白点,特地写下来,跟各位同学一起进步,同时也希望各位大神指导和指正。 多态的...