Java多态的实现原理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java多态的实现原理相关的知识,希望对你有一定的参考价值。

参考博客:

【解惑】Java动态绑定机制的内幕http://blog.csdn.net/zero_295813128/article/details/52117737

Java 虚拟机体系结构:http://hxraid.iteye.com/blog/676235

--------------------------------------------------------------------------------------------------

下面是自己的理解总结:

    首先得对两个概念有理解方法区和常量池。这两个都是Java虚拟在运行时的数据区域,常量池是方法区

的一部分。

方法区

    方法区与Java堆一样,是各个线程共享的内存区域,用于存储已经被虚拟机加载的类信息、常量、静态变

量、即使编译器编译后的代码等数据。

常量池

    常量池是方法区的一部分,用于存放编译期所生成的各种字面量和符号引用。常量池中共有11个常量表。

    常量表类型 标志值(占1 byte) 描述

    CONSTANT_Utf8     1 UTF-8编码的Unicode字符串

    CONSTANT_Integer 3 int类型的字面值

    CONSTANT_Float     4 float类型的字面值

    CONSTANT_Long     5 long类型的字面值

    CONSTANT_Double     6 double类型的字面值

    CONSTANT_Class     7 对一个类或接口的符号引用

    CONSTANT_String     8 String类型字面值的引用

    CONSTANT_Fieldref 9 对一个字段的符号引用

    CONSTANT_Methodref 10 对一个类中方法的符号引用

  CONSTANT_InterfaceMethodref 11 对一个接口中方法的符号引用

    CONSTANT_NameAndType 12 对一个字段或方法的部分符号引用

---------------------------------------------------------------------------------------------------

对于多态的原理主要研究方法区。在Java中多态指的是它允许基类的指针或引用指向派生类的对象,而在具体访

问时实现方法的动态绑定。java中的方法调用有静态绑定和动态绑定之分,静态绑定指的是我们在编译期就已经

确定了会执行那个方法的字节码,而动态绑定只有在运行时才能知晓。

静态绑定

    Java中的静态方法、私有方法以及final修饰的方法的调用,都属于静态绑定,对于重载的实例方法的

调用,也是采用静态绑定。静态绑定的原理主要是一个常量池解析的过程,下面来详解其过程:

    假如有两个类A、B,在A类中我们调用了B类中的一个静态方法,在编译期,这个调用的动作会被编译成一

条静态调用指令,该指令就对应常量池中的CONSTANT_Methodref表中所存储的该方法的符号引用,通过这个符号引用

可以得到静态方法的全类名B,JVM加载B类,便会得到B类中方法的直接地址,该地址会被存储到A类常量池中对应的

常量表中,这便是常量池解析过程,再次发起调用时,就会直接根据这个直接地址调用对应方法。

    以上过程可以看出,在编译阶段我们就已经确定了应该执行哪一个字节码代码。

动态绑定

    动态绑定讲解之前需要了解JVM管理的一个重要的数据结构--方法表。它以数组的形式记录了当前类及其所有

超类的可见方法字节码在内存中的直接地址 。

技术分享图片

    动态绑定前面的流程与静态绑定类似,假如此处有两个类A,B继承了A类,B类中重写了A类中的f1()方法,我们采用

向上转型的方式用指向B实例的A类型引用调用f1()方法,编译器会生成一条字节码指令,该指令会去常量表中找到f1()方法信

息的符号引用,通过该引用确定调用该方法的类型全名,即A类的全名称,根据名称加载到A类的字节码,去A类所对应的方法

表中找到f1()方法,将它的直接地址记录到调用f1()方法的类的对应的常量表中,常量池解析结束,可以思考,我们此时是否能

确定调用f1()方法时执行的是哪一块的字节码,答案是不能,因为截至此时我们f1()方法指定执行的是父类中的方法,引用虽然

父类类型,但他指向的是父类对象还是子类对象是不知道的(确切地说是此时的程序不知道,程序员肯定是知道的),假如指向父类

那就是父类中的f1()方法,如果指向子类的实例,子类没有重写,依然执行父类f1()方法,如果子类重写了就应该是子类的f1()

方法。此时动态绑定就登场了,确定f1()换需要拿到B类实例在堆中的引用,通过引用找到堆中B的对象,根据对象进一步获取它的

方法表,找到方法表的f1()方法的直接地址,此时便最终确定了。

以上是关于Java多态的实现原理的主要内容,如果未能解决你的问题,请参考以下文章

java多态理解和底层实现原理剖析

java多态实现原理

多态的原理是啥?

Java 中多态的实现原理

Java多态的实现原理

从虚拟机指令执行的角度分析JAVA中多态的实现原理