多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
多态存在的3个必要条件:
1.要有继承;
2.要有方法的重写;
3.父类引用指向子类对象;
示例代码:
class Polymorphic_Demo{
public static void main(String[] args) {
Cat c = new Cat(); //*********(1)
System.out.println(c.leg);
c.eat();
Animal a = new Cat(); //*********(2)
System.out.println(a.leg);
a.eat();
}
}
class Animal {
int leg = 2;
public void eat(){
System.out.println("动物吃东西");
}
}
class Cat extends Animal {
int leg = 4;
public void eat(){
System.out.println("猫吃鱼");
}
}
Cat c = new Cat()————这句代码仅仅是继承关系,不存在多态特性;
Animal a = new Cat()——-这句代码就展示了一种多态特性,猫是动物的一种表现形态;
输出结果:
分析一下:
变量输出:对象(1)输出leg为:4;对象(2)输出leg为:2;
方法输出:对象(1)输出leg为:猫吃鱼;对象(2)输出leg为:猫吃鱼;
这里就会疑惑了,为什么变量输出和方法输出的方式不太一样呢?
看一下main方法
public static void main(String[] args) {
Cat c = new Cat(); //*********(1)
System.out.println(c.leg);
c.eat();
Animal a = new Cat(); //*********(2)
System.out.println(a.leg);
a.eat();
}
解释下类中main方法的执行过程:
Polymorphic_Demo.class加载->main方法进栈->Animal.class加载->Cat.class加载-> 声明一个Cat类型变量c->创建Cat对象->输出c.leg变量4->执行Cat对象中的eat()方法->输出“猫吃鱼”—>创建Animal类变量a->创建Cat对象(且变量a指向此对象)->输出a.leg变量2
对象是Cat类变量,为什么输出leg却是Cat的父类Animal中的leg值呢?
因为在堆中创建子类对象时,其内部是这样的
在子类对象中有一块区域是super区域,存放继承父类的变量和方法,容易理解,变量a的类型是Animal类型,因此a.leg可以看做是super.leg,所以输出就是Animal.leg变量,即2。
下面接着执行->执行Cat对象中的eat()方法->输出“猫吃鱼”
这里又出现疑问了,按照上面对变量的讲解,不是应该输出父类方法中的内容吗?为什么这里输出子类方法中的内容呢?
下面就出现了一个名词:动态绑定(Dynamic Binding)
什么是动态绑定?在JVM执行到方法时,会根据这个方法所属变量类型标识符找到该方法的全限定名(包名+类名),这里所属变量类型是父类,但是只知道所属变量类型还不能够的,因为无法确定方法的具体位置(非静态方法肯定是在堆中),就无法压到栈中执行,因此必须根据父类变量创建的实际对象确定方法的具体位置(在堆中寻找),这种在程序执行过程中,通过动态创建的方法表来定位方法的方式,称为动态绑定。