前言:对于面向对象的三大特性,封装、继承与多态,前两者非常容易记住,但是对多态的记忆比较模糊。而且对于转型后的方法调用也比较模糊,今天再来总结下:
先给出定义:相同的类型实例调用同一个方法时候呈现出不同的行为特征,这就是多态(摘抄自疯狂java讲义)。
先用10秒看两个类:
1、父类
public class SuperA {
public SuperA(){
}
public void init(){
System.out.println("SuperA()-->init()");
}
}
2、子类
public class ChildB extends SuperA{
public void init(){
System.out.println("ChildB()-->init()");
}
}
然后我们进行向上转型
public class TestMain {
public static void main(String[] args) {
SuperA a1 = new SuperA();
SuperA a2 = new ChildB();
a1.init();
a2.init();
}
}
结果输出:同一个类型的两个对象,调用相同方法,表现出不同的行为。
SuperA()-->init()
ChildB()-->init()
向上转型:只能调用父类有的方法,且实际调用的是子类覆写过的方法。转型就好比假扮,子类向上假扮父类,那么它只能有父类的行为(不然就露馅了),也就是只能调用父类有的方法,但是它是假扮的,所以在调用方法的时候会表现出自己的行为(必然会露馅),于是就造成了都是相同的父类的实例,调用相同的方法会出现不同的行为,就是多态。并且方法才具有多态性,属性不具有多态性。
所以多态就是各个子类向上转型后,调用相同方法表现出不同行为的特性。
那么向下转型会不会有多态呢?答案是肯定的
再看一个孙子类
public class ChildC extends ChildB{
public void init(){
System.out.println("ChildC()-->init()");
}
}
再运行向下转型结果
public class TestMain {
public static void main(String[] args) {
SuperA a2 = new ChildB();
ChildB b2 = (ChildB)a2 ;
b2.init();
SuperA a3 = new ChildC();
ChildB b3 = (ChildB)a3 ;
b3.init();
}
}
输出结果:
ChildB()-->init()
ChildC()-->init()
向下转型注意:父类的实例,必须是对应子类的实例,才能把这个父类的实例对象向下转型,否则会报类型转换错误。
可以看出,相同的类型ChildB的实例,调用相同的方法表现除了不同的行为,所以也有多态特性。
总结:
1、转型得到的实例,都是调用子类覆写过的方法。
2、正是由于不同的类型实例转型到同一个父类类型,调用相同方法表现出不同行为就是多态。
3、只有方法才有多态,类的成员变量没有多态。
4、转型好比假扮,只有表现出被假扮者的行为,也就是只能调用父类有的方法。
5、多态是编译时对象与运行时对象不同造成的结果,编译时类型为父类,但是它被赋予了子类实例,也就是在运行时的类型发生了改变,就造成了多态的错觉。