1、类型转换
在前面的章节中,我们了解了父类和子类的关系,子类是对父类的扩展,父类是子类的抽象。也许同学们会有疑问,如果在程序中声明了一个父类变量,该父类变量能不能指向其子类对象呢?或者声明了一个子类变量,该子类变量能不能指向其父类对象呢?答案是肯定的。
例如下面的代码:
public class Product {
//产品名称
String name;
//产品价格
double price;
//产品作者
String author;
//产品摘要
String summary;
//构造方法
public Product()
{
}
}
public class EBook extends Product {
//电子图书的格式
String formation;
//电子图书的文件大小
long filesize;
public EBook() {
super();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//父类的变量指向其子类的对象
Product temp = new EBook();
//输出Fruits类的信息
}代码中Product类是父类,EBook是Product类的子类,在main方法中,声明了Product类变量,该变量指向实例化的子类对象,也就是父类变量指向其子类对象。因此,在继承关系中,子类的对象可以直接当作父类的对象使用,称为“向上转型”。
注意的是,子类对象当作父类对象使用时,不能访问其子类对象新增加的成员变量和方法。例如,在上面的例子代码中,父类变量temp指向其子类对象,因此,不能访问EBook类的formation和filesize属性。
既然父类变量可以指向子类对象。那么,父类对象也可以转换为子类对象,该转换称为“向下转型”,“向下转型”需要使用强制转换。将父类对象强制转换为子类对象时,必须确保该父类对象是子类的一个实例。
例如下面的代码:
public static void main(String[] args) {
// TODO Auto-generated method stub
//父类的变量指向其子类的对象
Product temp = new EBook();
// temp是EBook的实例,可以强制转换为子类对象
EBook ebook = (EBook) temp;
//父类的paper变量指向实例化的PaperBook对象
Product paper = new PaperBook();
//强制paper对象转换为EBook时,会发生异常
EBook ebook = (EBook) paper;
}语句“EBook ebook = (EBook) paper”在运行时,会抛出一个运行异常ClassCastException,表示类转换异常。因此,在进行父类向子类的转换时,一个好的习惯是通过instanceof运算符来判断父类变量是否是该子类的一个实例:
EBook book = null; if( paper instanceof EBook ) book = (EBook) paper;
2、动态绑定
动态绑定是Java多态的一种表现形式,指的是代码在执行期间而不是编译时判断所引用对象的实际类型,并根据其实际的类型,调用其相应的方法。
举个例子,家用电器包含电视、电脑、冰箱等电器设备,我们可以把家用电器抽象为类(Equipment),电视(ColorTv)、电脑(Computer)、冰箱(Icebox)是作为家用电器类的子类。家用电器类提供support()方法,表示家用电器已通电,但通电后,电视、电脑、冰箱有不同的表现形式,可以用重写父类support()方法的技术来解决这个问题,这就是java 的多态和动态绑定。
类对象的动态绑定需要满足如下条件:
(1)类与类之间有继承关系;
(2)子类重写了父类的方法;
(3)要有父类变量指向子类对象;
(4)要有父类变量调用重写的方法。
例如,下面的代码首先定义了一个电器类,然后分别定义它的两个子类:电视机和电脑,再定义一个判定类判定在程序动态运行时是哪台电器在运行,代码如下:
//电器类
public class Equipment {
public void support()
{
System.out.println("通电功能!");
}
}
//电视机类
class ColorTv extends Equipment
{
public void support()
{
System.out.println("电视机通电,看电视");
}
}
class Computer extends Equipment
{
public void support()
{
System.out.println("电脑通电,编写程序");
}
}
class Discriminate
{
public void judge(Equipment equi)
{
equi.support();
}
}
public class TestEquipment
{
public static void main(String[] args) {
// TODO Auto-generated method stub
Discriminate dis = new Discriminate();
//多态调用
dis.judge(new Computer() );
//多态调用
dis.judge(new ColorTv() );
}
}程序输出结果为:
电脑通电,编写程序
电视机通电,看电视
动态绑定的优点是当需要扩展程序功能,添加新的类时,不需要修改原来已经存在的类结构,只需要增加新的类即可。例如,如果要增加冰箱类,只需要重写电器类的support方法即可,代码如下:
class Icebox extends Equipment
{
public void support()
{
System.out.println("冰箱通电,可以冰冻事物");
}
}在上面的例子代码中,程序又增加了Icebox类,Icebox类重写了父类的support()方法。重修修改TestEquipment代码如下:
public class TestEquipment
{
public static void main(String[] args) {
// TODO Auto-generated method stub
Discriminate dis = new Discriminate();
//多态调用计算机
dis.judge(new Computer() );
//多态调用电视
dis.judge(new ColorTv() );
//多态调用冰箱
dis.judge(new Icebox () );
}
}由上面的代码可以看出,动态绑定可以很容易扩展程序功能,而无需改动原有的代码。
■ 知识点拨
多态和动态绑定实际上是让“做什么”和“怎么做”分离了,本文中的家用电器类(Equipment)只负责基础通电功能(support),而(support)的具体实现由电视(ColorTv)、电脑(Computer)、冰箱(Icebox)子类负责。因此,只要电器类通电,则其电视、电脑、冰箱就开始运行,至于运行的内容,则有电视、电脑、冰箱内部负责。
■ 思考与练习
应用eclipse开发工具建立Equipment项目,实现教材内容中的代码案例,体会动态绑定的用法。