Java对象类型的转换(向上转型+向下转型)
对象类型的转换在 Java 编程中经常遇到,主要包括向上转型与向下转型操作。
【实例】使用向上转型模拟如下场景:这里有一个人,名叫 tom,他是一名教师。

图 1 向上转型结合实例的说明
综上所述,因为人类(People)是教师类(Teacher)的父类,所以通过向上转型,能够把教师类(Teacher)类型的对象(new Teacher();)直接赋值给人类(People)类型的变量(tom)。
也就是说,进行向上转型,父类类型的对象可以引用子类类型的对象。而且,向上转型是安全的,因为向上转型是将一个较具体的类的对象转换为一个较抽象的类的对象。例如,可以说平行四边形是四边形,但不能说四边形是平行四边形。
那么,使用向上转型的过程中,父类的对象是否可以调用子类独有的属性或者方法呢?下面以父类四边形类的对象调用子类平行四边形类独有的属性为例,阐述这一问题。
例如,四边形类是平行四边形类的父类,用 Quadrangle 表示四边形类、用 Parallelogram 表示平行四边形类;在 Parallelogram 类中,定义一个值为 4 的表示底边长度的变量 edges;在 Parallelogram 类的主方法中,运用向上转型,把平行四边形类(Parallelogram)类型的对象直接赋值给四边形类(Quadrangle)类型的对象。
人为强制四边形类(Quadrangle)类型的对象可以调用变量 edges,并将 edges 的值修改为 6,Eclipse 能通过编译么?Eclipse的效果图如下图所示,从该图中可以看出,Eclipse 在相关代码处显示波浪线等错误标志,说明代码有误。

图 2 父类的对象是否可以调用子类独有的属性
综上所述,在运用向上转型的过程中,父类的对象无法调用子类独有的属性或者方法。
例如,可以说某只鸽子是一只鸟,却不能说某只鸟是一只鸽子。因为鸽子是具体的,鸟是抽象的。一只鸟除了可能是鸽子,还有可能是老鹰、麻雀等。因此,向下转型是不安全的。
【实例】编写代码证明“可以说某只鸽子是一只鸟,却不能说某只鸟是一只鸽子”。其中,鸟类是鸽子类的父类,用 Bird 表示鸟类,用 Pigeon 表示鸽子类。

图 3 向下转型时会发生的错误
如果想要告诉编译器“某只鸟就是一只鸽子”,应该如何修正?答案就是强制类型转换。也就是说,要想实现向下转型,需要借助强制类型转换。语法如下:
如果把上述实例中的代码:
虽然 Eclipse 没有提示编译错误,但运行程序后,控制台将输出如下错误信息:
Java向上转型
向上转型可以被理解为将子类类型的对象转换为父类类型的对象,即把子类类型的对象直接赋值给父类类型的对象,从而实现按照父类描述子类的效果。【实例】使用向上转型模拟如下场景:这里有一个人,名叫 tom,他是一名教师。
class People { } class Teacher extends People { } public class Demo3 { public static void main(String[] args) { People tom = new Teacher(); } }在上述代码中,“People tom = new Teacher();”运用了向上转型的语法,那么该如何理解这行代码的含义呢?理解方式如下图所示。

图 1 向上转型结合实例的说明
综上所述,因为人类(People)是教师类(Teacher)的父类,所以通过向上转型,能够把教师类(Teacher)类型的对象(new Teacher();)直接赋值给人类(People)类型的变量(tom)。
也就是说,进行向上转型,父类类型的对象可以引用子类类型的对象。而且,向上转型是安全的,因为向上转型是将一个较具体的类的对象转换为一个较抽象的类的对象。例如,可以说平行四边形是四边形,但不能说四边形是平行四边形。
那么,使用向上转型的过程中,父类的对象是否可以调用子类独有的属性或者方法呢?下面以父类四边形类的对象调用子类平行四边形类独有的属性为例,阐述这一问题。
例如,四边形类是平行四边形类的父类,用 Quadrangle 表示四边形类、用 Parallelogram 表示平行四边形类;在 Parallelogram 类中,定义一个值为 4 的表示底边长度的变量 edges;在 Parallelogram 类的主方法中,运用向上转型,把平行四边形类(Parallelogram)类型的对象直接赋值给四边形类(Quadrangle)类型的对象。
人为强制四边形类(Quadrangle)类型的对象可以调用变量 edges,并将 edges 的值修改为 6,Eclipse 能通过编译么?Eclipse的效果图如下图所示,从该图中可以看出,Eclipse 在相关代码处显示波浪线等错误标志,说明代码有误。

图 2 父类的对象是否可以调用子类独有的属性
综上所述,在运用向上转型的过程中,父类的对象无法调用子类独有的属性或者方法。
Java向下转型
向下转型可以被理解为将父类类型的对象转换为子类类型的对象。但是,运用向下转型,如果把一个较抽象的类的对象转换为一个较具体的类的对象,这样的转型通常会出现错误。例如,可以说某只鸽子是一只鸟,却不能说某只鸟是一只鸽子。因为鸽子是具体的,鸟是抽象的。一只鸟除了可能是鸽子,还有可能是老鹰、麻雀等。因此,向下转型是不安全的。
【实例】编写代码证明“可以说某只鸽子是一只鸟,却不能说某只鸟是一只鸽子”。其中,鸟类是鸽子类的父类,用 Bird 表示鸟类,用 Pigeon 表示鸽子类。
class Bird { } class Pigeon extends Bird { } public class Demo4 { public static void main(String[] args) { Bird bird = new Pigeon(); // 某只鸽子是一只鸟 Pigeon pigeon = bird; // 某只鸟是一只鸽子 } }本例在运行之前,Eclipse 会报出如下图所示的编译错误,这是因为父类对象不能直接赋值给子类对象。

图 3 向下转型时会发生的错误
如果想要告诉编译器“某只鸟就是一只鸽子”,应该如何修正?答案就是强制类型转换。也就是说,要想实现向下转型,需要借助强制类型转换。语法如下:
子类类型 子类对象 = (子类类型)父类对象;因此,要想实现把鸟类对象转换为鸽子类对象(相当于告诉编译器“某只鸟就是一只鸽子”),需要将图7.4中第8行代码修改为:
Pigeon pigeon = (Pigeon) bird; //通过强制类型转换,告诉编译器“某只鸟就是一只鸽子”需要注意以下两点:
- 两个没有继承关系的对象不可以进行向上转型或者向下转型;
- 父类对象可以强制转换为子类对象,但有一个前提:这个父类对象要先引用这个子类对象。
如果把上述实例中的代码:
Bird bird = new Pigeon(); // 某只鸽子是一只鸟 Pigeon pigeon = (Pigeon) bird; // 通过强制类型转换,告诉编译器“某只鸟就是一只鸽子”修改为如下代码:
Bird bird = new Bird(); // 某只鸟 Pigeon pigeon = (Pigeon) bird; // 通过强制类型转换,告诉编译器“某只鸟就是一只鸽子”
虽然 Eclipse 没有提示编译错误,但运行程序后,控制台将输出如下错误信息:
Exception in thread "main" java.lang.ClassCastException: class Bird cannot be cast to class Pigeon