1、多态概述:
多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定。
方法调用:多态中的方法调用分为两类,静态方法的调用和动态方法的调用。
(1)静态方法调用是指对于类的静态方法的调用方式,是在编译时刻就已经确定好具体调用方法的情况,是静态绑定的。
(2)动态方法调用需要有方法调用所作用的对象,是在调用的时候才确定具体的调用方法,是动态绑定的。
概念:
是指同一行为,具有多个不同表现形式。
多态前提:
继承或者实现【二选一】;方法的重写【意义体现:不重写,无意义】;父类引用指向子类对象【格式体现】
格式:
父类类型 变量名 = new 子类对象;
变量名.方法名();
ps:
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写 后方法。
2、从JVM的角度理解多态:
上面提到了如果父类方法中没有该方法就报错,有就执行子类方法。那么这是为什么呢?虚拟机怎么知道执行什么方法呢?下面我们将一一给出解答。
其实java虚拟机在执行java程序的时候,并不是直接运行的,他需要一个过程,我们使用一张图来看下:
这里我画一张java7的运行时数据区划分图,多态方法就存在了方法区。java堆存的是就是我们new出来的一个个实例对象,方法区存的就是类的类型信息。并且这个方法区中的类型信息跟在堆中存放的class对象是不同的。在方法区中,这个class的类型信息只有唯一的实例,而在堆中可以有多个该class对象。也就是说方法区的类型信息就是像一个模板,那些class对象就好比通过这些模板创建的一个个实例。
Father sonA=new SonA();
当我们输入以上代码时,就已经使用了多态。编译时时father,但运行后是sonA.
Father sonA是一个引用类型,存在了java栈中了;new SonA ,new一个实例对象,存储在了java堆中;SonA的类型信息存在了方法区中。具体如下图:
其实它的过程就是这样
每一个类都会有一个方法表,子类中不同的方法指向不同的类型信息。继承自Object的就指向Object,继承自Father的就指向Father。当Son类的方法表会有一个指向Father类的指针,同时也有一个指向自己方法的指针,这时候,新的数据会覆盖原有的数据。实现编译时是Father,运行是Son,也就实现了多态。
但是, 对于接口方法的调用是采用搜索方法表的方式,如,要在Father接口的方法表中找到dealHouse()方法,必须搜索Father的整个方法表。所以从效率上来说,接口方法的调用总是慢于类方法的调用的。