Logo

郎哥编程

Java类的类型转换和动态绑定

2018-03-30 743

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项目,实现教材内容中的代码案例,体会动态绑定的用法。


代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论