Java三大特性之一:多态
多态
一句话就是:父类型引用指向子类型对象
Java实现多态有三个必要条件:继承、重写、向上转型
1.继承:在多态中必须存在有继承关系的子类和父类。
2.重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
3.向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
对于Java而言,它多态的实现机制遵循一个原则:当父类对象引用变量引用子类对象时,被引用对象的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在父类中定义过的,也就是说被子类覆盖的方法。
总结这些概念,来个经典实例,如果弄懂了这个实例,多态也可以说是基本没问题了
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
public class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
public class C extends B{
}
public class D extends B{
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}
运行结果:
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D
在这里看结果1、2、3还好理解,从4开始就开始糊涂了,对于4来说为什么输出不是“B and B”呢?
首先我们先看一句话:当父类对象引用变量引用子类对象时,被引用对象的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在父类中定义过的,也就是说被子类覆盖的方法。
这句话对多态进行了一个概括。其实在继承链中对象方法的调用存在一个优先级:
this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
分析:
从上面的程序中我们可以看出A、B、C、D存在如下关系。
先来分析
④:a2.show(b),首先a2是父类型A指向子类型B,这里a2.show(b) = A.show(b),this指代了A类。A类没有找到,于是到A的父类找(A.super).show(b),由于A没有父类(Object不算)。所以来到第三级,this.show((super)b),来到b的父类A:A.show(A)。这里在A类中找到了show(A obj),但是由于a2指向了子类型对象B,同时B重写了show(A obj),因此最终会调用子类B类的show (A obj)方法。
⑤:和上同理,唯一的不同在于,来到第三级,this.show.((super)c)时,C的父类是B和A。所以存在两个分别是this.show(A obj),this.show(B obj),但是a2是父类型A指向子类型B,因此是找不到A类中的show(B obj),所以只执行了this.show(A obj)。并且因为子类型B重写了父类型方法show(A obj),结果也就是B and A
参考资料: