都知道多态是OO的一个特性。Java当中多态是靠接口实现和继承来实现,可分为编译时多态和运行时多态。
编辑时多态意指在编译时期就已经知道需要执行的具体是同名方法中的哪一个,如
Father f = new Father();
f.say();
运行时多态意指只有在运行时才知道需要执行的具体是同名方法中的哪一个,如
Father s = new Son();
s.say("Hello");
1. 接口实现多态:
interface A {
public String sayHello();
}
class B implements A
{
public String sayHello()
{
return "Hello B";
}
}
class C implements A
{
public String sayHello()
{
return "Hello C";
}
}
在调用时,用
A a1 = new B();
A a2 = new C();
这种方式来产生实例,用a1.sayHello()或a2.sayHello()时,就是多态的体现。
2. 继承实现多态:
Class A:
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
Class B:
public class B extends A{
public String show(B obj)
{
return "B and B";
}
public String show(A obj)
{
return "B and A";
}
}
Class C 和 D:
测试类:public class C extends B{}
public class D extends B{}
public class PolymorphismTest {
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(b));
System.out.println("a1.show(c) " + a1.show(c));
System.out.println("a1.show(d) " + a1.show(d));
System.out.println("a2.show(b) " + a2.show(b));
System.out.println("a2.show(c) " + a2.show(c));
System.out.println("a2.show(d) " + a2.show(d));
System.out.println("b.show(b) " + b.show(b));
System.out.println("b.show(c) " + b.show(c));
System.out.println("b.show(d) " + b.show(d));
}
}
输出结果:
这种在调用时,用父类作为类型声明,具体实例new的时候new的是子类,亦属多态体现。a1.show(b) A and A a1.show(c) A and A a1.show(d) A and D a2.show(b) B and A a2.show(c) B and A a2.show(d) A and D b.show(b) B and B b.show(c) B and B b.show(d) A and D
面对多态时,JVM方法调用优先级:
this.method(O), super.method(O), this.method((super)O), super.method((super)O)
按照这个顺序,必然能得到正确的JVM调用结果。
比如a2.show(b), this指的是class A,因为声明为A类,那么
1. this.method(O), 它找 A.show(B),结果没有
2. super.method(O), A类的super类是Object,显然没有Object.show(B)方法
3. this.method((super)O), 它找 A.show((super)B), 既是A.show(A),而该方法A类中有,然检查该方法是否被具体实现类(这里new的对象是B)重写overriding,如果有,调用overriding方法,即B.show(A)方法,所以打印"B and A"
注意,第三步中(super)O中是一个递归,它按照继承类实现回溯,比如如果调用的是a2.show(c),第三步时,它先找A.show((super)C), 即 A.show(B),没找到,再找A.show((super)B),即 A.show(A),而A.show(A)被B.show(A)重写,a2是B的具体实例,于是结果实际调用时B.show(A)方法,于是打印“B and A"
这里注意多态与重写、重载区别:
重写overriding:
子类中把父类同名、同参方法再实现一遍
重载:
子类中实现与父类中方法同名、异参方法
所以刚才这个例子中,既包含了多态,又包含了重写。
这里有个重写的陷阱例子:
public class Base
{
int i=99;
}
public class Child extends Base
{
int i =-1;
public static void main(String[] args])
{
Base b = new Child();
System.out.println(b.i);
}
}
如果把这个当作重写,就掉入陷阱了。重写是方法级的,变量无法override,所以输出是99.