Java向上转型和向下转型的区别(附带实例)
在 Java 程序中,对象的类型转换是指子类与父类之间的转换,主要包括如下两种:
将一个子类对象的引用转换为它父类的引用,称为向上转型。向上转型的语法格式如下:
由于子类通常包含比父类更多的成员变量和成员方法,因此任何一个从父类派生出的各种子类都可以作为父类的类型对待。也就是说,从一个特殊的、具体的类型到一个通用、抽象类型的转换,肯定是安全的。
向上转型使父类对象可以指向子类对象,但通过父类对象只能访问父类中定义的成员变量和成员方法,子类特有的部分成员被隐藏,不能被访问。只有将父类对象强制转换为具体的子类类型,才能访问子类的特有成员。
向下转型的语法格式如下:
针对这种情况,Java 语言中提供了 instanceof 关键字,可以先通过 instanceof 关键字来判断某个对象是否属于某种数据类型(类或接口),当前面的判断结果为 true 时再执行转换,其语法格式如下:
接下来,通过案例来演示向下转型:
注意,在使用 instanceof 运算符时,该运算符前面的操作数的编译时类型要么与后面的类型相同,要么与后面的类型具有继承关系,否则会引起编译错误。
- 向上转型:指从子类到父类的转换;
- 向下转型:指从父类到子类的转换。
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 运算符时,该运算符前面的操作数的编译时类型要么与后面的类型相同,要么与后面的类型具有继承关系,否则会引起编译错误。