该文内容为本人学习Java核心编程第七版时做的学习总结以及一些理解,部分内容为翻译过来的。
1. 多态(polymorphism)
在面向对象的编程里面,多态是一个出现频率比较高的术语,那么多态到底是指什么
呢?一个对象变量(object variable,与基本数据类型的变量相对应)可以指向(refer to)多个类型的对象,这就是多态。以下面的代码为例:
public class PolymorphicTest {
public PolymorphicTest() {
}
public void setName(String n){
this.name=n;
System.out.println(“在父类中”);
}
public String getName(){
return this.name;
}
private String name;
}
public class PolymorphicChild extends PolymorphicTest {
public void setArea(String a){
this.area=a;
}
public String getArea(){
return this.area;
}
//public void setName(String n){
// super(“n”);
// System.out.pirngln(“在子类中”);
// }
public static void main(String[] args) {
PolymorphicChild child=new PolymorphicChild();
PolymorphicTest test[]=new PolymorphicTest[2];
test[0]=child;
test[0].setName(“zhukai”);
test[1]=new PolymorphicTest();
}
private String area;
}
test[0]声明为一个PolymorphicTest的变量,但是它可以refer to一个PolymorphicChild类型的对象(如child),当然它也肯定可以refer to一个PolymorphicTest类型的对象,因为它本身就是这个类型的,例如test[1]。为什么会这样呢?一般来说,一个对象变量可以指向(refer to)任意一个它自己所属类型及其子类型的对象,有一个有名的(is-a)规则,类似于我国古代的“白马非马”这个典故。它就是说,任何一个子类的对象都可以说成是其父类的一个对象,但是反之则不一定了,例如,我们可以说白马是马,但是不能说马是白马。这个规则的另外一个表示方法就是“替换”准则:凡是程序中需要用到父类对象的地方,我们都可以用其子类的对象来进行替换。
接下来,就产生了一个问题,我们调用test[0]的setName(String n)方法的时候,它调用的到底是PolymorphicTest类还是PolymorphicChild类的setName方法呢?这就涉及到动态绑定的问题了,对象如何自动的选择合适的方法来执行?
2. 动态绑定(Dynamic Binding)
以上一节中的test[0].setName(String n)为例,我们现在有语句test[0].setName(“zhukai”),
那么它的执行过程是什么样的呢?
第一步:查看test[0]声明的类型,即PolymorphicTest类,然后获得方法名setName,接着把PolymorphicTest类中的所有名字为setName的方法以及其父类中所有名字为setName的public方法列出来。若没有名为setName的方法,则调用失败,否则转第二步。
第二步:根据所调用方法的参数类型来对上一步所列出来的所有方法进行匹配,直到找到一个匹配的转第三步,如果没有匹配则调用失败。
第三步:若test[0]所指向(refer to)的对象的类型为其一个子类,则需查看子类有没有覆盖该方法,若有,则执行子类中的方法。
注1:如果这个方法是private或者static或者final类型的,就不用进行动态绑定了,因为编译器可以很准确的知道要调用哪个方法。
注2:查询匹配方法时,是按照继承树逐级向上查找,直到找到第一个匹配的。
以上就是动态绑定的过程。
以上面的程序为例,程序执行时,当执行test[0].setName(“zhukai”)时,将会输出“在父类中”,如果去掉PolymorphicChild中的注释,此时将会先输出“在父类中”,然后再输出“在子类中”。