精华内容
下载资源
问答
  • 2021-02-27 19:49:57

    一个对象变量可以指示多种实际类型的现象称为多态

    允许不同类的对象对同一消息做出响应。方法的重载、类的覆盖正体现了多态。

    1、多态的机制

    1.1 本质上多态分两种

    1、编译时多态(又称静态多态)2、运行时多态(又称动态多态)

    重载(overload 发生在一个类中,方法名必须相同,不同参数)就是编译时多态的一个例子,编译时多态在编译时就已经确定,运行时运行的时候调用的是确定的方法。

    我们通常所说的多态指的都是运行时多态,也就是编译时不确定究竟调用哪个具体方法,一直延迟到运行时才能确定。这也是为什么有时候多态方法又被称为延迟方法的原因。

    下面简要介绍一下运行时多态(以下简称多态)的机制。

    1.2 多态通常有两种实现方法

    1、子类继承父类(extends)2、类实现接口(implements)

    无论是哪种方法,其核心之处就在于对父类方法的改写或对接口方法的实现,以取得在运行时不同的执行效果。

    要使用多态,在声明对象时就应该遵循一条法则:声明的总是父类类型或接口类型,创建的是实际类型。

    2、多态的实现原理

    下面从虚拟机运行时的角度来简要介绍多态的实现原理,这里以Java虚拟机(Java Virtual Machine, JVM)规范的实现为例。

    在JVM执行Java字节码时,类型信息被存放在方法区中,通常为了优化对象调用方法的速度,方法区的类型信息中增加一个指针,该指针指向一张记录该类方法入口的表(称为方法表),表中的每一项都是指向相应方法的指针。

    方法表的构造如下:

    由于Java的单继承机制,一个类只能继承一个父类,而所有的类又都继承自Object类。方法表中最先存放的是Object类的方法,接下来是该类的父类的方法,最后是该类本身的方法。这里关键的地方在于,如果子类改写了父类的方法,那么子类和父类的那些同名方法共享一个方法表项,都被认作是父类的方法。

    注意这里只有非私有的实例方法才会出现,并且静态方法也不会出现在这里,原因很容易理解:静态方法跟对象无关,可以将方法地址直接引用,而不像实例方法需要间接引用。

    更深入地讲,静态方法是由虚拟机指令invokestatic调用的,私有方法和构造函数则是由invokespecial指令调用,只有被invokevirtual和invokeinterface指令调用的方法才会在方法表中出现。

    由于以上方法的排列特性(Object——父类——子类),使得方法表的偏移量总是固定的。例如,对于任何类来说,其方法表中equals方法的偏移量总是一个定值,所有继承某父类的子类的方法表中,其父类所定义的方法的偏移量也总是一个定值。

    前面说过,方法表中的表项都是指向该类对应方法的指针,这里就开始了多态的实现:

    假设Class A是Class B的子类,并且A改写了B的方法method(),那么在B的方法表中,method方法的指针指向的就是B的method方法入口。

    而对于A来说,它的方法表中的method方法则会指向其自身的method方法而非其父类的(这在类加载器载入该类时已经保证,同时JVM会保证总是能从对象引用指向正确的类型信息)。

    结合方法指针偏移量是固定的以及指针总是指向实际类的方法域,我们不难发现多态的机制就在这里:

    在调用方法时,实际上必须首先完成实例方法的符号引用解析,结果是该符号引用被解析为方法表的偏移量。虚拟机通过对象引用得到方法区中类型信息的入口,查询类的方法表,当将子类对象声明为父类类型时,形式上调用的是父类方法,此时虚拟机会从实际类的方法表(虽然声明的是父类,但是实际上这里的类型信息中存放的是子类的信息)中查找该方法名对应的指针(这里用“查找”实际上是不合适的,前面提到过,方法的偏移量是固定的,所以只需根据偏移量就能获得指针),进而就能指向实际类的方法了。

    我们的故事还没有结束,事实上上面的过程仅仅是利用继承实现多态的内部机制,多态的另外一种实现方式:实现接口相比而言就更加复杂,原因在于,Java的单继承保证了类的线性关系,而接口可以同时实现多个,这样光凭偏移量就很难准确获得方法的指针。所以在JVM中,多态的实例方法调用实际上有两种指令:

    invokevirtual指令用于调用声明为类引用的方法;

    invokeinterface指令用于调用声明为接口的方法。

    当使用invokeinterface指令调用方法时,就不能采用固定偏移量的办法,只能老老实实挨个找了(当然实际实现并不一定如此,JVM规范并没有规定究竟如何实现这种查找,不同的JVM实现可以有不同的优化算法来提高搜索效率)。我们不难看出,在性能上,调用接口引用的方法通常总是比调用类的引用的方法要慢。这也告诉我们,在类和接口之间优先选择接口作为设计并不总是正确的。

    更多相关内容
  • Java多态实现原理

    多人点赞 2021-06-03 16:06:38
    Java多态实现原理的大致过程:首先是Java编译器将Java源代码编译成class文件。在编译过程中,会根据静态类型将调用的符号引用写到class文件中。在执行时,JVM根据class文件找到调用方法的符号引用,然后在静态类型的...

    ##前言
    多态是Java语言重要的特性之一,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定。Java对于方法调用动态绑定的实现主要依赖于方法表,但通过引用调用(invokevitual)和接口引用调用(invokeinterface)的实现则有所不同。

    Java多态实现原理的大致过程:首先是Java编译器将Java源代码编译成class文件。在编译过程中,会根据静态类型将调用的符号引用写到class文件中。在执行时,JVM根据class文件找到调用方法的符号引用,然后在静态类型的方法表中找到偏移量,然后再根据this指针确定对象的实际类型,使用实际类型的方法表(偏移量跟静态类型中的偏移量一样是指 就是用的静态类型中的偏移量,因为符号引用在静态类型的方法表中找到的偏移量是同一个),如果在实际的方法中找到该方法(说明参数值对上了)则直接调用,否则认为没有重写父类的方法则按照继承关系从下往上搜索来调用方法。

    image

    程序运行时,需要某个类是,类载入系统会将相应的class文件载入到JVM中,并在内部建立该类的 类型信息 (这个类型信息其实就是class文件在JVM中存储的一种数据结构),包含java类定义的所有信息(方法代码、类和成员变量、以及实现动态调用的核心 - 方法表 )。这个类型信息存储在方法区。

    注意:这个方法去中的类型信息跟在堆中存放的class对象是不同的。在方法区中,这个class的类型信息只有唯一的实例(所以是各个线程共享的内存区域),而在堆中可以有多个该class对象。可以通过堆中的class对象访问到方法去中的类型信息(像Java的反射机制,通过class对象可以访问到该类的所有信息)。

    【重点】

    方法表是实现动态调用的核心。上面讲过方法表存放在方法区中的类型信息中。为了优化对象调用方法的速度,方法区的类型信息会增加一个指针,该指针指向一个记录该类方法的方法表,方法表中的每一个项都是对应方法的指针。
    这些方法中包括从父类继承的所有方法以及自身重写(override)的方法。

    【拓展】

    方法区:方法区和JAVA堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 
    运行时常量池:它是方法区的一部分,Class文件中除了有类的版本、方法、字段等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种符号引用,这部分信息在类加载时进入方法区的运行时常量池中。 
    方法区的内存回收目标是针对常量池的回收及对类型的卸载。

    #####Java 的方法调用方式

    Java 的方法调用有两类,动态方法调用与静态方法调用。

    • 静态方法调用是指对于类的静态方法的调用方式,是静态绑定的
    • 动态方法调用需要有方法调用所作用的对象,是动态绑定的。

    类调用 (invokestatic) 是在编译时就已经确定好具体调用方法的情况。

    实例调用 (invokevirtual)则是在调用的时候才确定具体的调用方法,这就是动态绑定,也是多态要解决的核心问题。

    JVM 的方法调用指令有四个,分别是 invokestatic,invokespecial,invokesvirtual 和 invokeinterface。前两个是静态绑定,后两个是动态绑定的。本文也可以说是对于JVM后两种调用实现的考察。

    方法表与方法调用

    如有类定义 Person, Girl, Boy

    class Person {
        public String toString() {
            return "I'm a person.";
        }
        public void eat() {
        }
        public void speak() {
        }
    }
    
    class Boy extends Person {
        public String toString() {
            return "I'm a boy";
        }
        public void speak() {
        }
        public void fight() {
        }
    }
    
    class Girl extends Person {
        public String toString() {
            return "I'm a girl";
        }
        public void speak() {
        }
        public void sing() {
        }
    }
    

    当这三个类被载入到 Java 虚拟机之后,方法区中就包含了各自的类的信息。Girl 和 Boy 在方法区中的方法表可表示如下:

    可以看到,Girl 和 Boy 的方法表包含继承自 Object 的方法,继承自直接父类 Person 的方法及各自新定义的方法。注意方法表条目指向的具体的方法地址,如 Girl 继承自 Object 的方法中,只有 toString() 指向自己的实现(Girl 的方法代码),其余皆指向 Object 的方法代码;其继承自于 Person 的方法 eat() 和 speak() 分别指向 Person 的方法实现和本身的实现。

    如果子类改写了父类的方法,那么子类和父类的那些同名的方法共享一个方法表项。

    因此,方法表的偏移量总是固定的。所有继承父类的子类的方法表中,其父类所定义的方法的偏移量也总是一个定值。
    Person 或 Object中的任意一个方法,在它们的方法表和其子类 Girl 和 Boy 的方法表中的位置 (index) 是一样的。这样 JVM 在调用实例方法其实只需要指定调用方法表中的第几个方法即可。

    如调用如下:

    class Party {
        void happyHour() {
            Person girl = new Girl();
            girl.speak();
        }
    }
    

    当编译 Party 类的时候,生成 girl.speak()的方法调用假设为:    Invokevirtual #12

    设该调用代码对应着 girl.speak(); #12 是 Party 类的常量池的索引。JVM 执行该调用指令的过程如下所示:

    (这里有个错误,上图为ClassReference常量池而非Party的常量池)
    【再次拓展】

    常量池在逻辑上可以分成多个表,每个表包含一类的常量信息,本文只探讨对于 Java 调用相关的常量池表。

    CONSTATNT_Method_info**:**类方法引用表;包含引用的任何类型方法的描述信息,主要包括类信息索引和名字类型索引。

    CONSTATNT_Class_info**:**类信息表;包含任何被引用的类或接口的 ‘符号引用’ ,每一个条目主要包含一个索引,指向CONSTA_Utf8_info表,表示该类或接口的全限定名。

    CONSTATNT_NameAndType_info:名字类型表;包含引用的任意方法或字段的名称和描述符信息在字符串常量中的索引。

    CONSTATNT_Utf8_info:字符串常量表; 该表包含该类所使用的所有字符串常量,比如代码中的字符串引用、引用的类名、方法的名字、其他引用的类与方法的字符串描述等等。其余常量池表中所涉及到的任何常量字符串都被索引至该表。

    可以看到,给定任意一个方法的索引,在常量池中找到对应的条目后,可以得到该方法的类索引(classindex)和名字类型索引 (nameandtypeindex), 进而得到该方法所属的类型信息和名称及描述符信息(参数,返回值等)——从而通过对方法的类型信息和名称及描述符信息(参数,返回值等)来确定具体是调用哪一个方法。

    JVM执行  Invokevirtual #12 指令的过程:

    (1)在常量池中找到方法调用的符号引用。 JVM 首先查看 Party(应为ClassReference常量池) 的常量池索引为 12 的条目 (此条目即指 - 查看常量池中的CONSTATNT_Method_info表,即类方法引用表),再 进一步查看常量池中的(CONSTANTClassinfo,CONSTANTNameAndTypeinfo ,CONSTANTUtf8info) 三个表。

    (2) 可得出要调用的方法是 Person 的 speak 方法, 查看 Person 的方法表,得出 speak 方法在该方法表中的偏移量 15,这就是该方法调用的直接引用。

    (3) 根据this指针得到具体的对象(即girl所指向位与堆中的对象)

    (4)根据对象得到该对象对应的方法表,根据偏移量15查看有无重写(override)该方法,如果重写,则可以直接调用(Girl的方法表的speak项指向自身的方法而非父类);如果没有重写,则需要拿到按照继承关系从下往上的基类(这里是Person类)的方法表,同样按照这个偏移量15查看有无该方法。
    ##最后
    以上,是对Java多态实现原理翻阅两篇博文后为便于理解而整理而出。
    参考博文:
    https://www.cnblogs.com/kaleidoscope/p/9790766.html
    https://zhuanlan.zhihu.com/p/94086109
    大家看完有什么不懂的可以在下方留言讨论.
    谢谢你的观看。

    参考博文:
    https://www.cnblogs.com/kaleidoscope/p/9790766.html
    https://zhuanlan.zhihu.com/p/94086109
    大家看完有什么不懂的可以在下方留言讨论.
    谢谢你的观看。

    展开全文
  • JAVA中多态性是对象多种表现形式的体现。在面向对象中,最常见的多态发生在使用父类的引用来引用子类的对象。下面这篇文章主要给大家介绍一下,需要的朋友可以参考下
  • 大厂面试真题向来是求职者的最佳练兵场,华为在Java开发工程师招聘中有哪些技术性考察和倾向?那今天咱就给大家分享一下近期的华为5面面经! 注:以下所分享的华为面试问题,相关的答案我也整理出来了,且为了更加...

    前言

    大厂面试真题向来是求职者的最佳练兵场,华为在Java开发工程师招聘中有哪些技术性考察和倾向?那今天咱就给大家分享一下近期的华为5面面经!

    image

    注:以下所分享的华为面试问题,相关的答案我也整理出来了,且为了更加方便给想要进大厂的小伙伴一些帮助,我还专门准备了全套的《Java面试合集》(文末可见),全都是一丢一丢的收集整理纯手打出来的——并收整在我的GitHub上

    个人基本情况:

    首先介绍一下自己的个人基本情况,某专科学校毕业,计算机技术与应用专业,有过2年的工作经验,毕业以后一直想要进入一线互联网大厂工作,但无奈学历受限,屡屡被挡在门外。后来接触到一个朋友,了解到“霸面”,所以鼓起勇气去尝试了,挑战了一下蚂蚁金服,没想到经过4轮面试之后,居然拿到了offer,现特分享一下自己的面试真题,希望能够给你有所帮助。

    专科程序员“霸面”蚂蚁金服,4轮面试,竟拿下offer(Java方向)

    一面真题

    • 项目介绍
    • 项目中如何保证数据一致性的
    • 项目中存在的问题
    • JVM内存
    • 程序计算器的作用
    • gc 算法,垃圾收集器
    • Spring事务,事务的实现机制,如何保证事务的?
    • 悲观锁、乐观锁
    • HashMap
    • 红黑树,B+树
    • 死锁,如何防止死锁?

    二面真题

    二面之前做了一些题,做完题之后,二面围绕题目展开。

    • 分布式事务的保证,具体的解决方案
    • 接口的幂等性
    • 如果向某个账户转账,在高并发的环境下,设计的接口有什么问题?
    • 如何解决上述问题?
    • 如果账户表很大,具有亿万级别,如何提高查询效率?
    • 分库分表具体操作
    • MySQL主从
    • MySQL如何保证主从的数据一致性
    • 数据库的容灾

    三面真题

    主要是项目介绍

    项目一(支付营销系统):

    • 介绍、架构、具体流程,如何压测?性能优化?机器扩容标准、线程池大小
    • 平时用到的集合
    • Hashmap
    • Treeset的实现
    • 分布式事务
    • 秒杀系统

    项目二(分布式调度系统):

    • 项目具体情况、架构、设计思路
    • Kafka消息可靠性保证
    • 其他中间件
    • 平时看什么书

    四面(HR面)

    • 自我介绍?
    • 之前的工作给你带来了什么?
    • 之前在工作者承担什么样的角色?
    • 为什么想来蚂蚁金服?
    • 自己有什么优势?
    • 未来的职业规划是怎么样的?
    • 期待薪资多少?
    • 还有什么想问的?

    最后如何让自己一步步成为技术专家

    说句实话,如果一个打工人不想提升自己,那便没有工作的意义,毕竟大家也没有到养老的年龄。

    当你的技术在一步步贴近阿里p7水平的时候,毫无疑问你的薪资肯定会涨,同时你能学到更多更深的技术,交结到更厉害的大牛。

    推荐一份Java架构之路必备的学习笔记,内容相当全面!!!

    成年人的世界没有容易二字,前段时间刷抖音看到一个程序员连着加班两星期到半夜2点的视频。在这个行业若想要拿高薪除了提高硬实力别无他法。

    你知道吗?现在有的应届生实习薪资都已经赶超开发5年的程序员了,实习薪资26K,30K,你没有紧迫感吗?做了这么多年还不如一个应届生,真的非常尴尬!

    进了这个行业就不要把没时间学习当借口,这个行业就是要不断学习,不然就只能被裁员。所以,抓紧时间投资自己,多学点技术,眼前困难,往后轻松!

    要领取这些精心整理出来的资料的话,请记得

    进了这个行业就不要把没时间学习当借口,这个行业就是要不断学习,不然就只能被裁员。所以,抓紧时间投资自己,多学点技术,眼前困难,往后轻松!

    要领取这些精心整理出来的资料的话,请记得

    ————【关注】+【转发】+【点赞】支持我!创作不易!点击这里前往我的腾讯文档免费下载

    展开全文
  • java多态实现原理

    万次阅读 多人点赞 2016-07-22 16:46:24
    C++ 和 Java 作为当前最为流行的两种面向对象编程语言,其内部对于多态的支持到底是如何实现的呢,本文对此做了全面的介绍。 注意到在本文中,指针和引用会互换使用,它们仅是一个抽象概念,表示和另一个对象的...

    众所周知,多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定。C++ 和 Java 作为当前最为流行的两种面向对象编程语言,其内部对于多态的支持到底是如何实现的呢,本文对此做了全面的介绍。

    注意到在本文中,指针和引用会互换使用,它们仅是一个抽象概念,表示和另一个对象的连接关系,无须在意其具体的实现。

    Java 的实现方式

    Java 对于方法调用动态绑定的实现主要依赖于方法表,但通过类引用调用和接口引用调用的实现则有所不同。总体而言,当某个方法被调用时,JVM 首先要查找相应的常量池,得到方法的符号引用,并查找调用类的方法表以确定该方法的直接引用,最后才真正调用该方法。以下分别对该过程中涉及到的相关部分做详细介绍。

    JVM 的结构

    典型的 Java 虚拟机的运行时结构如下图所示

    图 1.JVM 运行时结构
    图 1.JVM 运行时结构

    此结构中,我们只探讨和本文密切相关的方法区 (method area)。当程序运行需要某个类的定义时,载入子系统 (class loader subsystem) 装入所需的 class 文件,并在内部建立该类的类型信息,这个类型信息就存贮在方法区。类型信息一般包括该类的方法代码、类变量、成员变量的定义等等。可以说,类型信息就是类的 Java 文件在运行时的内部结构,包含了改类的所有在 Java 文件中定义的信息。

    注意到,该类型信息和 class 对象是不同的。class 对象是 JVM 在载入某个类后于堆 (heap) 中创建的代表该类的对象,可以通过该 class 对象访问到该类型信息。比如最典型的应用,在 Java 反射中应用 class 对象访问到该类支持的所有方法,定义的成员变量等等。可以想象,JVM 在类型信息和 class 对象中维护着它们彼此的引用以便互相访问。两者的关系可以类比于进程对象与真正的进程之间的关系。

    Java 的方法调用方式

    Java 的方法调用有两类,动态方法调用与静态方法调用。静态方法调用是指对于类的静态方法的调用方式,是静态绑定的;而动态方法调用需要有方法调用所作用的对象,是动态绑定的。类调用 (invokestatic) 是在编译时刻就已经确定好具体调用方法的情况,而实例调用 (invokevirtual) 则是在调用的时候才确定具体的调用方法,这就是动态绑定,也是多态要解决的核心问题。

    JVM 的方法调用指令有四个,分别是 invokestatic,invokespecial,invokesvirtual 和 invokeinterface。前两个是静态绑定,后两个是动态绑定的。本文也可以说是对于 JVM 后两种调用实现的考察。

    常量池(constant pool)

    常量池中保存的是一个 Java 类引用的一些常量信息,包含一些字符串常量及对于类的符号引用信息等。Java 代码编译生成的类文件中的常量池是静态常量池,当类被载入到虚拟机内部的时候,在内存中产生类的常量池叫运行时常量池。

    常量池在逻辑上可以分成多个表,每个表包含一类的常量信息,本文只探讨对于 Java 调用相关的常量池表。

    CONSTANT_Utf8_info

    字符串常量表,该表包含该类所使用的所有字符串常量,比如代码中的字符串引用、引用的类名、方法的名字、其他引用的类与方法的字符串描述等等。其余常量池表中所涉及到的任何常量字符串都被索引至该表。

    CONSTANT_Class_info

    类信息表,包含任何被引用的类或接口的符号引用,每一个条目主要包含一个索引,指向 CONSTANT_Utf8_info 表,表示该类或接口的全限定名。

    CONSTANT_NameAndType_info

    名字类型表,包含引用的任意方法或字段的名称和描述符信息在字符串常量表中的索引。

    CONSTANT_InterfaceMethodref_info

    接口方法引用表,包含引用的任何接口方法的描述信息,主要包括类信息索引和名字类型索引。

    CONSTANT_Methodref_info

    类方法引用表,包含引用的任何类型方法的描述信息,主要包括类信息索引和名字类型索引。

    图 2. 常量池各表的关系
    图 2. 常量池各表的关系

    可以看到,给定任意一个方法的索引,在常量池中找到对应的条目后,可以得到该方法的类索引(class_index)和名字类型索引 (name_and_type_index), 进而得到该方法所属的类型信息和名称及描述符信息(参数,返回值等)。注意到所有的常量字符串都是存储在 CONSTANT_Utf8_info 中供其他表索引的。

    方法表与方法调用

    方法表是动态调用的核心,也是 Java 实现动态调用的主要方式。它被存储于方法区中的类型信息,包含有该类型所定义的所有方法及指向这些方法代码的指针,注意这些具体的方法代码可能是被覆写的方法,也可能是继承自基类的方法。

    如有类定义 Person, Girl, Boy,

    清单 1
     class Person { 
     public String toString(){ 
        return "I'm a person."; 
    	 } 
     public void eat(){} 
     public void speak(){} 
    	
     } 
    
     class Boy extends Person{ 
     public String toString(){ 
        return "I'm a boy"; 
    	 } 
     public void speak(){} 
     public void fight(){} 
     } 
    
     class Girl extends Person{ 
     public String toString(){ 
        return "I'm a girl"; 
    	 } 
     public void speak(){} 
     public void sing(){} 
     }

    当这三个类被载入到 Java 虚拟机之后,方法区中就包含了各自的类的信息。Girl 和 Boy 在方法区中的方法表可表示如下:

    图 3.Boy 和 Girl 的方法表
    图 3.Boy 和 Girl 的方法表

    可以看到,Girl 和 Boy 的方法表包含继承自 Object 的方法,继承自直接父类 Person 的方法及各自新定义的方法。注意方法表条目指向的具体的方法地址,如 Girl 的继承自 Object 的方法中,只有 toString() 指向自己的实现(Girl 的方法代码),其余皆指向 Object 的方法代码;其继承自于 Person 的方法 eat() 和 speak() 分别指向 Person 的方法实现和本身的实现。

    Person 或 Object 的任意一个方法,在它们的方法表和其子类 Girl 和 Boy 的方法表中的位置 (index) 是一样的。这样 JVM 在调用实例方法其实只需要指定调用方法表中的第几个方法即可。

    如调用如下:

    清单 2
     class Party{ 
    …
     void happyHour(){ 
     Person girl = new Girl(); 
     girl.speak(); 
    …
    	 } 
     }

    当编译 Party 类的时候,生成 girl.speak()的方法调用假设为:

    Invokevirtual #12

    设该调用代码对应着 girl.speak(); #12 是 Party 类的常量池的索引。JVM 执行该调用指令的过程如下所示:

    图 4. 解析调用过程
    图 4. 解析调用过程

    JVM 首先查看 Party 的常量池索引为 12 的条目(应为 CONSTANT_Methodref_info 类型,可视为方法调用的符号引用),进一步查看常量池(CONSTANT_Class_info,CONSTANT_NameAndType_info ,CONSTANT_Utf8_info)可得出要调用的方法是 Person 的 speak 方法(注意引用 girl 是其基类 Person 类型),查看 Person 的方法表,得出 speak 方法在该方法表中的偏移量 15(offset),这就是该方法调用的直接引用。

    当解析出方法调用的直接引用后(方法表偏移量 15),JVM 执行真正的方法调用:根据实例方法调用的参数 this 得到具体的对象(即 girl 所指向的位于堆中的对象),据此得到该对象对应的方法表 (Girl 的方法表 ),进而调用方法表中的某个偏移量所指向的方法(Girl 的 speak() 方法的实现)。

    接口调用

    因为 Java 类是可以同时实现多个接口的,而当用接口引用调用某个方法的时候,情况就有所不同了。Java 允许一个类实现多个接口,从某种意义上来说相当于多继承,这样同样的方法在基类和派生类的方法表的位置就可能不一样了。

    清单 3
    interface IDance{ 
       void dance(); 
     } 
    
     class Person { 
     public String toString(){ 
       return "I'm a person."; 
    	 } 
     public void eat(){} 
     public void speak(){} 
    	
     } 
    
     class Dancer extends Person 
     implements IDance { 
     public String toString(){ 
       return "I'm a dancer."; 
    	 } 
     public void dance(){} 
     } 
    
     class Snake implements IDance{ 
     public String toString(){ 
       return "A snake."; 
    	 } 
     public void dance(){ 
     //snake dance 
    	 } 
     }
    图 5.Dancer 的方法表(查看大图
    图 5.Dancer 的方法表

    可以看到,由于接口的介入,继承自于接口 IDance 的方法 dance()在类 Dancer 和 Snake 的方法表中的位置已经不一样了,显然我们无法通过给出方法表的偏移量来正确调用 Dancer 和 Snake 的这个方法。这也是 Java 中调用接口方法有其专有的调用指令(invokeinterface)的原因。

    Java 对于接口方法的调用是采用搜索方法表的方式,对如下的方法调用

    invokeinterface #13

    JVM 首先查看常量池,确定方法调用的符号引用(名称、返回值等等),然后利用 this 指向的实例得到该实例的方法表,进而搜索方法表来找到合适的方法地址。

    因为每次接口调用都要搜索方法表,所以从效率上来说,接口方法的调用总是慢于类方法的调用的。

    展开全文
  • Java多态实现原理

    2021-02-12 12:54:07
    多态的使用大家应该都比较了解,但是多态实现原理就有点抽象了,查了很多很多资料,连续几天断断续续的看,有时候看着看着就走神了。毕竟太抽象,哈哈~不过依然硬着头皮看下来了(也不知道看了多少遍),并且将很多...
  • Java多态实现原理

    2022-01-05 10:50:13
    1、什么是多态 多态是一个类的多种形式;...3、多态实现原理 通过invoke指令调用方法,基于class 4、什么是方法表 方法表存放方法地址,通过invoke指令调用对应方法,如果没有重写方法调用父类里的方法 ...
  • Java多态实现原理

    2022-05-08 11:16:33
    JAVA多态底层实现 底层实现是动态绑定,即在运行时才把方法调用与方法实现关联起来。调用类方法时,基于对象引用的类型来选择所调用的方法;调用实例方法时,基于对象实际的类型来选择所调用的方法。而动态绑定又...
  • JAVA多态实现原理浅析

    2018-11-05 11:23:47
    Java 中使用多态特性的方法主要有,实现一个接口,实现抽象类的一个方法,覆盖父类的一个方法。   多态的底层实现是动态绑定,即在运行时才把方法调用与方法实现关联起来。动态绑定涉及很多 JVM 的细节,全部写...
  • java 多态实现原理

    2019-04-30 14:57:55
    java 多态实现原理 有两种方式来实现多态,一种是编译时多态,另一种是运行时多态;编译时多态时通过方法的重载来实现的,运行时多态是通过方法的重写来实现的。 方法的重载,指的是同一个类中有多个同名的方法...
  • Java多态原理

    2021-03-28 15:08:51
    多态实现原理 为了更好地理解多态的原理,首先必须对jvm内存模型、Java方法调用等知识有点了解。 0. 什么是多态 多态分为两种,本文着重讲解运行时多态。 编译时多态。也叫做静态多态,指的是方法的重载,在同一...
  • java多态底层实现原理

    2020-03-30 14:24:12
    1.Java多态概述 多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定。Java对于方法调用动态绑定的实现主要依赖于方法表,但通过类引用调用...
  • Java多态实现原理

    千次阅读 2021-08-26 16:59:08
    这里的接口不应理解得太死板,比如在 Java 里面,继承一个类和实现一个接口本质上都是一种继承行为,因此都可以理解为多态的体现。 从静态和动态的角度进行划分,多态可以分为编译时多态和运行时多态。 编译时多态...
  • Java技术——多态实现原理

    万次阅读 多人点赞 2016-08-12 15:19:12
    多态Java技术里有很重要的地位,在面试中也会经常被问到。 但是多态太抽象了,查了很多很多资料,连续几天断断续续的看,有时候看着看着就走神了。毕竟太抽象,哈哈~ 不过依然硬着头皮看下来了(也不知道看了多少...
  • 学习多态之前可以先把继承了解一下:继承实现原理 我们学习多态一定要明确下面这几点注意事项 一、什么是多态 多态就是对同一个对象,在不同时刻表现出来的不同形态 格式:父类 变量名 = new 子类 ​ 变量名....
  • Java 多态的底层原理

    2021-02-12 14:33:00
    Java 中使用多态特性的方法主要有,实现一个接口,实现抽象类的一个方法,覆盖父类的一个方法。多态的底层实现是动态绑定,即在运行时才把方法调用与方法实现关联起来。动态绑定涉及很多 JVM 的细节,全部写清楚需要...
  • java多态的理解及实现原理

    千次阅读 2020-02-25 19:01:21
    3.如果需要,那么它是怎么实现的,原理是什么 4.如何使用和使用场景是什么? 下面开始回答上面的问题,额,好吧,这个是我百度了好多地方然后结合自己理解搞的,不过基本就是这个意思 先从1搞起: 官方是说: ...
  • Java方法的存储机制当JVM执行Java字节码时,类型信息会存储在方法区中,为了优化对象的调用方法的速度,方法区的类型信息会增加一个指针,该指针指向一个记录该类方法的方法表,方法表中的每一个项都是对应方法的...
  • Java多态实现机制

    2011-04-14 23:33:33
    Java多态实现机制,多态是java的三大属性之一,开发中很重要的一个环节
  • Java多态的底层实现原理

    千次阅读 2019-09-28 20:12:20
    多态的前提: 1.继承 2.重写 3.向上转型(这里的向上转型即父类型的引用指向子类型的实例) 二.类的加载 首先得介绍一下JVM的大体结构: 类先被加载进来。。。。。。(类的加载过程)得到class文件 class文件...
  • Java基础(多态实现原理)

    万次阅读 多人点赞 2022-04-22 12:50:32
    Java基础(多态实现原理)
  • 从虚拟机角度看Java多态->(重写override)的实现原理
  • java多态的底层原理

    千次阅读 2019-05-09 20:40:16
    虚拟机运行角度解释多态实现原理 动态绑定、方法表 将一个方法调用同一个方法主体关联起来被称作绑定,JAVA中分为前期绑定和后期绑定(动态绑定) 在程序执行之前进行绑定(由编译器和连接程序实现)叫做前期绑定 ...
  • 出神入化——SpringCloudAlibaba.pdf SpringCloud微服务架构笔记(一).pdf SpringCloud微服务架构笔记(二).pdf SpringCloud微服务架构笔记(三).pdf SpringCloud微服务架构笔记(四).pdf Dubbo框架RPC实现原理....
  • 1、多态的机制1.1 本质上多态分两种1、编译时多态(又称静态多态)2、运行时多态(又称动态多态)重载(overload 发生在一个类中,方法名必须相同,不同参数)就是编译时多态的一个例子,编译时多态在编译时就已经确定,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 50,127
精华内容 20,050
关键字:

java多态实现原理

java 订阅