本篇开始列举几个小程序帮助理解总结的几条多态特性:
(1)成员变量:编译看左边,运行看左边
(2)成员方法:编译看左边,运行看右边 (动态绑定)
(3)静态方法:编译看左边,运行看左边
(4)父类引用指向子类变量,引用不能使用子类特有的属性和方法
例一:
package java多态;
class 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 Polymorphic2 {
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(a1.show(b)); // 使用a1的成员函数show(A)
System.out.println(a1.show(c)); // 使用a1的成员函数show(A)
System.out.println(a1.show(d)); // 使用a1的成员函数show(D)
System.out.println(a2.show(b)); // 使用覆盖后的show(A)
System.out.println(a2.show(c)); // 使用覆盖后的show(A)
System.out.println(a2.show(d)); // 使用继承的show(D)
System.out.println(b.show(b)); // 使用B的show(B)
System.out.println(b.show(c)); // 使用B的show(B)
System.out.println(b.show(d)); // 使用A的show(D)
}
}
a1.show()比较好理解,因为A a1 = new A();编译看左边是A,类A中有show()方法,因此可以保证编译通过。因为是非静态方法调用,因此运行看右边仍然是A类中的方法调用,运行时对show(X)方法的确定通过参数列表来选择具体执行哪个show()方法,show(b)和show(c)在A类中没有直接定义,但是类A是类B和类C的父类,因此执行的是show(A),而show(D)在类A中有定义,因此执行show(A)。
a2.show():首先A a2 = new B();编译看左边,类A中含有show()方法,因此可以保证编译通过。因为是非静态方法调用,因此运行时看右边,也就是运行时需要调用类B中的方法。分析运行结果前我们首先要明确的是父类引用指向子类对象时,这个引用不能调用子类中特有的(也就是父类中没有的属性和方法),这么看来类B中特有的方法就是show(B obj)了,也就是说类B中可以使用的方法有类B中自己的show(A obj)(当然这个方法覆盖掉了类A中的show(A obj)),还可以使用类A中继承下来的show(D obj)这两个方法。
下面输出结果就很明显了:
a2.show(b)调用的show()方法是本类中的show(A obj),虽然类B中有show(B obj)但是这个引用访问不到这个方法噢。
a2.show(c)调用的同样是本类中的show(A obj),
a2.show(d)调用继承类A中的show(D obj)方法。
b.show():因为B b = new B();编译看左边有show(),编译通过;运行看右边仍然是类B中的方法。此时类B中的方法除了show(B obj)和show(A obj)外,还有从类A中继承下来的show(D obj)总共这三个show()方法的重写。
b.show(b),类B中有show(B obj)这个方法,直接调用
b.show(c),类B中没有直接重写的show(C obj),因此看C的父类是B,类B中有show(B obj),因此直接调用
b.show(d),类B中没有,但是继承的类A中有,因此调用类A中的show(D obj)。