Java多态的底层实现原理

一.什么是多态?对于多态的理解?

允许具有继承关系的不同类的对象去调用同一函数方法,并且会根据对象的不同产生多种状态的行为方式。或者说是一个接口的不同实现方式。在java里,继承一个类和实现一个接口本质上都是一种继承行为,因此都应该理解为多态的体现。

二.多态的前提:

1.继承 2.重写 3.向上转型(即父类型的引用指向子类型的实例)

三.多态的实现原理:

知道了什么是多态,那要解释多态在底层是如何实现的,只要去发掘程序是如何确定出自己真正的实例就好了。多态的底层实现是依靠动态绑定,(其实是我们在这里只谈论动多态)即在运行时才把方法调用与方法实现联系起来。以一个例子为例:

class Father {
    public void test(){
        System.out.println("This is Father");
    }
}

 class Son extends Father {
    @Override
    public void test(){
        System.out.println("This is Son");
    }
}

public class TestDemo {
        public static void main(String[] args) {
            Father s = new Son();
            s.test();
        }
    }

大家肯定都知道最后的的打印结果是“This is Son”,我们在这里要讨论的是这个过程是如何实现的
Java多态的底层实现原理_第1张图片
如上图所示,当我们在执行代码的时候,首先根据我们所写的语法在栈内存上会创建相对应的引用变量s,相应地在堆内存上开辟空间创建Son的实例对象,并且引用s指向它的实例Son,由类的加载过程我们可知道我们所编写的Class文件会在JVM方法区上建立储存它所含有的类型信息(成员变量、类变量、方法等)并且还会得到一个Class对象(通过反射机制)建立在堆区上,该Class对象会作为方法区访问数据的入口。

方法区

方法区是与多态的实现最密切相关的区域,该类的类型信息会被保存在方法区中,并且为了优化对象调用方法的速度,方法区中的类型信息中会增加一个指针,该指针会去指向一张记录该类方法入口的表,即方法表,并且方法表中的每一项都是指向相应方法的指针。
JAVA语言是单继承机制,一个类只能继承一个父类,而所有的类又都继承自Object类。方法表有自己的存储机制:方法表中最先存放的是Object类的方法,接下来是父类的方法,最后才是自身特有的方法。这里的关键点在于如果子类重写了父类的方法,那么子类和父类的同名方法共享一个方法表项,都被认作是父类的方法(仅仅只有非私有的实例方法才行,静态方法是不行的),即同名(子类重写的)方法在相对应类的方法表中的偏移量是相同的。

所以我要说重点了:

结合同名方法偏移量相同且是固定的,则在调用方法时,首先会对实例方法的符号引用进行解析,解析的结果就是方法表的偏移量。当我们把子类对象声明为父类类型时,明面上虚拟机通过对象引用的类型得到该类型方法区中类型信息的入口,去查询该类型的方法表(即例中的Father),得到的是父类型的方法表中的test方法的偏移量,但实际上编译器通过类加载过程获取到Class对象知道了实例对象s的真正类型,转而进入到了真正的子类类型(例中的Son)的方法表中用偏移量寻找方法,恰好两者偏移量是相等的,我们就顺利成章的拿到了Son类型方法表中的test方法进而去指向test方法入口。嘻嘻。

四.多态的好处:

1.应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。(继承保证)
2.派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,
可以提高可扩充性和可维护性。(多态保证)

你可能感兴趣的:(Java基础)