细节24 小心谨慎——向上转型与向下转型
在编程过程中,经常需要进行对象类型的转换,在Java中,对象类型转换可以分为向上转型和向下转型两种,为了防止向下转型出错,还可以通过instanceof运算符判断父类对象能否转换为子类对象。
1.向上转型
向上转型是指从子类对象到父类对象的类型转换,这种转换由系统自动完成,也就是说将子类对象赋值给父类对象的引用,系统自动完成从子类对象到父类对象的转换,这种转换称为向上转型。
注意
当子类对象向上转型为父类对象后,就不能再通过父类对象的引用来访问子类对象中新增的属性和方法了,但是可以访问子类重写的父类中的属性和方法。
父类Animal的代码示例:
public class Animal { public void cry (){ // 父类的cry ()方法 System. out. println ("动物会叫"); // 输出信息 } }
子类Dog的代码示例:
public class Dog extends Animal { public void cry () { // 子类重写父类的cry ()方法 super. cry (); // 调用父类Animal的cry ()方法 System. out. println ("狗汪汪叫"); // 输出信息 } public void shikar (){ // 子类新增的shikar ()方法 System. out. println ("狗能狩猎"); // 输出信息 } }
进行向上转型:
❶Animal animal = new Dog (); // 子类Dog向上转型为父类Animal ❷animal. cry (); // 转型后的可以访问子类重写父类的方法cry () ❸//animal. shikar (); // 转型后的父类对象不能访问子类新增的方法shikar ()
说明
上面的代码在标记❶处将子类Dog创建的对象向上转型为父类Animal类型,然后在标记❷处,调用了子类Dog重写父类的cry ()方法,即父类对象调用子类Dog中的cry ()方法,此时程序会执行Dog 类中cry ()方法体的第一行代码super. cry (),即调用Animal 类的cry ()方法,输出“动物会叫”,然后继续往下执行,又输出了“狗汪汪叫”。其中,需要将标记❸处调用子类新增的shikar ()方法的代码注释掉,因为不能通过向上转型后的父类对象调用子类中新增的方法,因此,将标记❸处的代码注释掉了。
2.向下转型
向下转型是指从父类对象到子类对象的类型转换,这种转换通常都会产生错误,因为只有那些通过子类对象创建的父类对象才可以向下转型为子类对象。
提示
为了避免向下转型时出错,可以通过instanceof运算符判断父类对象是否能转换为子类对象,如果父类对象能向下转型为子类对象,instanceof 运算符将返回真值true,这时就可以通过强制类型转换,将父类对象向下转型为子类对象。
父类Animal的代码示例:
public class Animal { public void cry (){ // 父类的cry ()方法 System. out. println ("动物会叫"); // 输出信息 } }
子类Dog的代码示例:
public class Dog extends Animal { public void cry () { // 子类重写父类的cry ()方法 super. cry (); // 调用父类Animal的cry ()方法 System. out. println ("狗汪汪叫"); // 输出信息 } public void shikar (){ // 子类新增的shikar ()方法 System. out. println ("狗能狩猎"); // 输出信息 } }
实现向下转型:
❶//Dog dog = (Dog) new Animal (); // 错误的向下转型 ❷Animal animal = new Dog (); // 子类向上转型为父类对象 ❸Dog dog = (Dog) animal; // 将向上转型的父类对象向下转型为子类对象 dog. cry (); // 调用子类的cry ()方法 dog. shikar (); // 调用子类的shikar ()方法
说明
上面的代码将标记❶处的语句注释掉了,这是因为该语句直接将父类对象向下转型为子类对象时,发生了类型不匹配的错误,在标记❷处创建子类Dog的实例并赋值给父类Animal的引用,然后在标记❸处将animal强制转换为子类对象dog,实现了向下转型,接着就可以通过dog调用子类Dog中的方法了。
注意
由于向下转型容易出错,所以在进行向下转型时,应尽量使用instanceof运算符判断所要转换的父类对象是否为子类对象的实例,如果是,就可以执行向下转型的代码,完成向下转型。
将上面实现向下转型的代码修改如下,这样就可以防止向下转型时出错了。
Animal animal = new Dog (); // 子类向上转型为父类对象 if (animal instanceof Dog){ // 判断是否可以向下转型 Dog dog = (Dog) animal; // 将向上转型的父类对象向下转型为子类对象 dog. cry (); // 调用子类的cry ()方法 dog. shikar (); // 调用子类的shikar ()方法 }