首页 > 编程笔记 > Java笔记 阅读:10

Java向上转型和向下转型的区别(附带实例)

在 Java 程序中,对象的类型转换是指子类与父类之间的转换,主要包括如下两种:

Java向上转型

类的继承关系使子类具有父类的成员变量和成员方法,这意味着父类的成员可以在它的派生子类中使用,也就是说子类的对象也是父类的对象,子类对象既可以作为该子类的类型也可以作为父类的类型。

将一个子类对象的引用转换为它父类的引用,称为向上转型。向上转型的语法格式如下:
父类|接口 对象名 = new 子类();
举个简单的例子,Pet 是 Cat 的父类,参考代码如下:
Pet p = new Cat();
p.eat();      // 调用子类的eat()方法
向上转型体现的是“is a”关系。例如,一个 Cat 类的对象(猫)是一个 Pet 类(宠物)的对象,这是没有问题的,因为 Cat 类继承了 Pet 类的成员变量和成员方法,这意味着 Pet 类的对象 p 调用 eat() 方法时,可以完成相应的操作。

由于子类通常包含比父类更多的成员变量和成员方法,因此任何一个从父类派生出的各种子类都可以作为父类的类型对待。也就是说,从一个特殊的、具体的类型到一个通用、抽象类型的转换,肯定是安全的。

Java向下转型

向下转型也称为对象的强制类型转换,是指将父类对象类型的变量强制转换为子类类型。

向上转型使父类对象可以指向子类对象,但通过父类对象只能访问父类中定义的成员变量和成员方法,子类特有的部分成员被隐藏,不能被访问。只有将父类对象强制转换为具体的子类类型,才能访问子类的特有成员。

向下转型的语法格式如下:
子类 对象名 = (子类)父类对象;
参考代码如下:
Pet p =  new Pet();
Dog d1 = new Dog();
Dog d2;
// d2 = (Dog)p; 这种写法转换失败,因为p指向的类型是Pet,d2的引用类型为Dog
// 下面的写法正确,首先将p的引用指向d2,此时的p的类型变成了Dog,所以同类型之间可以转换
p = d2;
d2 = (Dog)p;
向下转型可以调用子类类型中所有的成员,不过需要注意的是,如果父类引用对象指向的是子类对象,那么向下转型的过程是安全的,也就是编译时不会出错误。但是,如果父类引用对象是父类本身,那么向下转型的过程是不安全的,编译不会出错,但是运行时会出现 Java 强制类型转换异常。

针对这种情况,Java 语言中提供了 instanceof 关键字,可以先通过 instanceof 关键字来判断某个对象是否属于某种数据类型(类或接口),当前面的判断结果为 true 时再执行转换,其语法格式如下:
引用类型变量 instanceof 类名|接口

接下来,通过案例来演示向下转型:
class Pet { // 宠物类
    private String name = "无名"; // 昵称
    private int health = 100; // 健康值
    public void eat() {}
}

class Dog extends Pet { // 狗类继承自宠物类
    public void eat() { // 重写eat()方法
        System.out.println("狗狗在啃骨头");
    }
}

class Cat extends Pet { // 猫类继承自宠物类
    public void eat() {
        System.out.println("猫咪在吃鱼干");
    }
}

class Master {
    private String name; // 主人的姓名

    public void feed(Pet p) { // 主人喂宠物,具体类型由传入的类型决定
        p.eat();
    }
}

public class Demo {
    public static void main(String[] args) {
        Pet p = new Dog(); // 向上转型
        if (p instanceof Dog) { // 判断对象是否是Dog类型
            Dog o = (Dog) p; // 向下转型
            o.eat();
        } else if (p instanceof Cat) { // 判断对象是否是Cat类型
            Cat c = (Cat) p; // 向下转型
            c.eat();
        }
    }
}
程序的运行结果如下:

狗狗在啃骨头

通过程序运行结果可发现,instanceof 能准确判断出对象是否是某个类的实例,有效地防止了运行时异常的发生,提高了程序的健壮性。

注意,在使用 instanceof 运算符时,该运算符前面的操作数的编译时类型要么与后面的类型相同,要么与后面的类型具有继承关系,否则会引起编译错误。

相关文章