向下转型
与向上转型相对应的就是向下转型了。向下转型是把父类对象转为子类对象。
向下转型注意事项
- 向下转型的前提是父类对象指向的是子类对象(也就是说,在向下转型之前,它得先向上转型)
-
向下转型只能转型为本类对象
案例:
lass A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{
}
class D extends B{
}
public class Demo {
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));
}
}
当父类对象引用变量引用子类对象时,被引用对象的类型决定了调用谁的成员方法,引用变量类型决定可调用的方法。如果子类中没有覆盖该方法,那么会去父类中寻找。
实例
class X {
public void show(Y y){
System.out.println("x and y");
}
public void show(){
System.out.println("only x");
}
}
class Y extends X {
public void show(Y y){
System.out.println("y and y");
}
public void show(int i){
}
}
class main{
public static void main(String[] args) {
X x = new Y();
x.show(new Y());
x.show();
}
}
Y 继承了 X,覆盖了 X 中的 show(Y y) 方法,但是没有覆盖 show() 方法。
这个时候,引用类型为X的 x 指向的对象为 Y,这个时候,调用的方法由 Y 决定,会先从 Y 中寻找。执行 x.show(new Y());
,该方法在 Y 中定义了,所以执行的是 Y 里面的方法;
但是执行 x.show();
的时候,有的人会说,Y 中没有这个方法啊?它好像是去父类中找该方法了,因为调用了 X 中的方法。
事实上,Y 类中是有 show() 方法的,这个方法继承自 X,只不过没有覆盖该方法,所以没有在 Y 中明确写出来而已,看起来像是调用了 X 中的方法,实际上调用的还是 Y 中的。
这个时候再看上面那句难理解的话就不难理解了吧。X是引用变量类型,它决定哪些方法可以调用;show()和 show(Y y) 可以调用,而 show(int i)不可以调用。Y 是被引用对象的类型,它决定了调用谁的方法:调用 y 的方法。
上面的是一个简单的知识,它还不足以让我们理解那个复杂的例子。我们再来看这样一个知识:
继承链中对象方法的调用的优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
如果你能理解这个调用关系,那么多态你就掌握了。我们回到那个复杂的例子:
abcd 的关系是这样的:C/D —> B —> A
我们先来分析4 : a2.show(b)
- 首先,a2是类型为A的引用类型,它指向类型为B的对象。A确定可调用的方法:show(D obj)和show(A obj)。
a2.show(b)
==>this.show(b)
,这里this指的是B。- 然后.在B类中找show(B obj),找到了,可惜没用,因为show(B obj)方法不在可调用范围内,
this.show(O)
失败,进入下一级别:super.show(O)
,super指的是A。 - 在A 中寻找show(B obj),失败,因为没用定义这个方法。进入第三级别:
this.show((super)O)
,this指的是B。 - 在B中找show((A)O),找到了:show(A obj),选择调用该方法。
- 输出:B and A
- 首先,b为类型为B的引用对象,指向类型为B的对象。没有涉及向上转型,只会调用本类中的方法。
- 在B中寻找show(D obj),方法。现在你不会说没找到了吧?找到了,直接调用该方法。
- 输出 A and D。
总结
- 多态,简而言之就是同一个行为具有多个不同表现形式或形态的能力。
- 多态的分类:运行时多态和编译时多态。
- 运行时多态的前提:继承(实现),重写,向上转型
- 向上转型与向下转型。
- 继承链中对象方法的调用的优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。