多态性又叫动态绑定、推迟绑定或运行期绑定。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
多态的基石--上溯造型:
interface Animal{ //动物接口
void play(){};
}
class Dog implements Animal{ //狗类
void play(){
System.out.println("Dog");
}
}
class Cat implements Animal{ //猫类
void play(){
System.out.println("Cat");
}
}
public class Test{
void play(Animal a){ //参数为动物接口
a.play();
}
public static void main(String[] args){
Dog dog = new Dog();
Cat cat = new Cat();
play(dog); //传入狗类
play(cat); //传入猫类
}
}
为什么要用上溯造型?那上面的代码为例,如果不用上溯造型,则Test类中要写两个play()方法,参数分别为狗类和猫类。如果衍生类增加,play()方法的个数也要增加。使用上溯造型可以不管衍生类,只需要跟基础类打交道,省下很大的工作量。
深入理解动态绑定:Test类的play()方法接收一个Animal句柄,那么它是怎么知道这个句柄是指向Dog还是Cat的呢?这必须在运行期间才能确定。所以在运行之前进行的绑定叫做“早期绑定”,在运行期进行的绑定叫做“动态绑定”。Java中方法的绑定都是动态绑定,除非一个方法被声明为final.
下面这条语句成立也是因为动态绑定:
Animal a = new Dog();
下溯造型:
上溯造型会丢失具体的类型信息,所以为了获取具体的类型信息可以使用 “下溯造型”。然而,上溯造型肯定 是安全的;基础类不可能再拥有一个比衍生类更大的接口。因此,我们通过基础类接口发送的每一条消息都 肯定能够接收到。但在进行下溯造型的时候并不一定安全。
class Useful {
public void f() {}
}
class MoreUseful extends Useful {
public void f() {}
public void g() {}
}
public class RTTI {
public static void main(String[] args) {
Useful[] x = {
new Useful(),
new MoreUseful() //上溯造型
};
((MoreUseful)x[0]).g(); //下溯造型报错 Exception thrown
((MoreUseful)x[1]).g(); //下溯造型成功
}
}
如上代码所示,衍生类上溯造型会丢失数据,但再下溯造型回来后这些数据还存在。上述代码也表示下溯造型并不一定是安全的。
下一篇:多态性之抽象类和接口