1、什么是多态
面向对象编程的三大特性:封装、继承、多态。换一个角度看,多态是封装和继承的必要条件。
概念:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单的说: “一个接口,多种实现”。说白了,就是一个引用在调用方法时,具体调用的是哪个方法取决与其引用的对象类型,当对象类型不同时,调用不同的方法,这就是多态。这是由于方法的重写产生的多态现象,另外方法重载也体现了多态的特性。
2、关于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...{}
该列子比较长,为了方便说明,我自己写了一个更简单的例子
class A {
void show(A a) {
System.out.println("A and A");
}
}
class B extends A {
void show(B b) {
System.out.println("B and B");
}
}
问题:
A a = new B();
a.show(new B());
运行结果:
A and A
讨论:
乍一看,结果应该是“B and B”才对,此时this指向的是对象B,实参也为B类型,结果却是“A and A”。
在此之前,我们先看一下这段话:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,(但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。)
我把最重要也是最容易被忽略的一部分用括号括起来了,我们常在多态中说,对象的类型决定了方法的动态绑定,但是这有一个很关键的前提,就是该方法是否被重写了,也就是括号中文字所表达的内容。
那么我们应如何判断方法调用时的动态绑定:
首先,我们先了解一下在继承链中对象方法调用的一个优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
针对上述例子,我们来看一下,我们已经拥有了一个A类的引用,此时调用show(new B())方法,注意,这时千万不要先看B类中的方法,因为引用是A类型的,所以我们从A类型开始判断,可以这样假设,此时的this指向A,当然这只是一种帮助理解的方式,this真正指向的是B。我们依照方法调用的优先级,A.show(B),A中并无该方法,然后是super.show(B),A并无父类,那么跳过该项,来到A.show((super)B),A中有该方法,即A.show(A a),当找到该方法之后,动态绑定其实还没结束,这时再来看this真正指向的对象其实是B,则判断B中是否覆盖了.show(A a)方法,并没有,到这一步,方法调用已最终确定,即A类中的.show(A a)方法,执行结果自然是“A and A”。
3、总结
this决定动态绑定的前提是该方法已在this所指向的对象中被覆盖了,对于一个在超类中未定义的方法,当对象被向上类型转换时,该方法会丢失,超类引用是无法看见该方法的,也无法调用,此时动态绑定不成立!