美文网首页
java动态绑定和多态实现原理

java动态绑定和多态实现原理

作者: tracy_668 | 来源:发表于2018-03-31 11:22 被阅读20次

     在java方法调用过程中,jvm是如何知道具体调用哪个类的方法? 我们常常听到的静态和动态方法调用有什么区别呢?他们底层的原理是什么?本文将围绕这几个问题展开。

静态绑定:

       上面的源代码中Father.f1()被编译成 invokestatic #13, #13表示StaticCall类的常量池中第13个常量表的索引项,它记录着方法f1的符号引用,包括f1所在的类名,方法名以及返回类型,jvm首先会根据这个符号引用找到方法f1所在的类的全限定名。然后会加载、链接和初始化Father类,接着会在Father类所在的方法区中找到f1()方法的直接地址,并将这个直接地址记录到StaticCall类常量池索引为13的索引项中。这个过程叫常量池解析,以后每次调用 Father.f1()时,jvm将直接找到f1方法的字节码,并开始解释执行。

      上述中,经过常量池解析后,jvm就能够确定调用的f1()方法具体在内存的什么位置,实际上这个信息在第一次解析后就已经在StaticCall类的常量池中记录了下来,这种在解析一次后就能够确定所调用方法的地址的方式叫做静态绑定机制。

除了被static修饰的静态方法,所有被private修饰的私有方法,被final修饰的禁止子类覆盖的方法都会被编译成invokestatic指令,所有类的初始化方法会被编译成invokespecial指令,jvm采用静态绑定机制来调用这些方法。

动态绑定机制:

jvm是如何知道f.f1()调用的是子类Sun中的方法而不是Father中的方法?

     我们知道在jvm加载类的同时,会在方法区为这个类存放很多信息,其中有一个数据结构叫方法表,它以数组的形式记录了当前类及其所有超类的可见方法字节码在内存的直接地址。

该方法表有两个特点,1: 子类方法表中继承了父类的方法 2: 相同的方法在所有类的方法表中的索引相同。

编译器会把上面main方法编译成下面字节码指令:

其中invokevirtual的指令的详细调用过程如下:

(1)invokevirtual指令中的#15指的是AutoCall类的常量池中的第15个索引项,它记录者方法f1信息的符号引用,jvm首先会根据这个符号引用找到f1的类全限定名,Father, 而不是son是因为调用方法f1的类的对象father声明为Father类型。

(2)在Father类型的方法表中查找方法f1,如果找到,则将方法f1在方法表中的索引项11记录到 AutoCall类的常量池中第15个常量表中(常量池解析),如果Father类型方法表中没有方法f1,即使son类型中方法表有,也会报错!

(3)在invokevirtual指令前有一个aload_1指令,它会把在堆中Son对象的引用压入操作数栈,invokevirtual指令会根据这个son对象引用找到堆中的son对象,然后进一步找到son对象所属类型的方法表,再根据步骤2完成解析的常量表#15的内容11,可以定位到son类型方法表中的方法f1(),可找到该方法字节码所在的内存空间。

    这种通过实际对象所在类的方法表每次来定位方法在内存的具体位置的方式,叫做动态绑定机制,与静态绑定相比,动态绑定的字节码指令在解析常量池时并不会解析出方法具体在内存的位置,而是一个该方法在方法表上的索引,具体调用时根据传入对象的具体类来找到方法在内存的具体位置。

进阶

Father类型中并没有方法签名为f1(char)的方法,但最后却是调用了Father类型中的f1(int)方法,并没有调用到Son类型中的f1(char)方法。实际上,jvm会根据参数的自动转型来找到合适的方法,找到 Father类型中的f1(int),Son类型中并没有重写f1(int)方法,所以还是调用Father的f1(int)方法。

       这个同上一样,jvm会选择合适的方法去调用。选择标准是:如果一个方法可以接受传递给另一个方法的任何参数,那么该方法就相对不合适,应该选择参数范围更小的方法。

总结

       简单地说,静态绑定就是只需要解析一次就能够确定方法在内存的位置,所以可看成是静态的。而动态绑定常量池解析不会解析出方法在内存的具体地址,只是解析出一个方法在方法表上的索引位置,具体在内存的地址需要根据传入的对象的具体类型来确定,也即是动态确定的。

相关文章

  • java动态绑定和多态实现原理

    在java方法调用过程中,jvm是如何知道具体调用哪个类的方法? 我们常常听到的静态和动态方法调用有什么区别呢...

  • 深刻剖析之c++博客文章

    三大特性 封装、继承、多态 多态 C++ 虚函数表解析C++多态的实现原理 介绍了类的多态(虚函数和动态/迟绑定)...

  • java类型转换

    这部分可以说是java的灵魂。它的实现原理其实不是很复杂:动态绑定。但在java中有一套强大多态运用的体系,其中涵...

  • Java基础每日10题——第二天

    1.Java中实现多态的机制是什么? 动态绑定 2.Java中异常分为哪些种类 RuntimeException、...

  • Java多态和动态绑定

    在Java中,父类的变量可以引用父类的实例,也可以引用子类的实例。 请读者先看一段代码: 运行结果:不知道怎么叫喵...

  • 第八章:多态

    多态分离做什么和怎么做,将接口和实现分离开来。也称为动态绑定、后期绑定或运行时绑定。

  • Java基础之面向对象

    1.多态,继承,封装 Java实现多态有哪些必要条件?具体怎么实现?多态的实现原理?多态的作用? 答:多态的优点 ...

  • Java多态和动态绑定是如何实现的

    https://www.cnblogs.com/ShaneZhang/p/4972550.html

  • 动态绑定

    动态绑定 我们都知道多态是java的最重要的特性。 Fruit fruit = new Apple();;frui...

  • Java静态分派、动态分派、双重分派

    动态分派和静态分派机制是java多态的实现原理。 静态分派(方法重载) 静态分派机制最典型的代码: 这段代码执行完...

网友评论

      本文标题:java动态绑定和多态实现原理

      本文链接:https://www.haomeiwen.com/subject/xceicftx.html