Java 引用变量有两个类型。如果编译时类型和运行时类型不一致,就可能出现多态。
编译时类型:由声明该变量时使用的类型决定
运行时类型:由实际运行时赋给该变量的对象决定
向上类型转换
示例代码:
1 | public class BaseClass { |
上面的例子中,引用变量 ploymophicBc 比较特殊,它的编译时类型是 BaseClass,而运行时类型是 SubClass。
ploymophicBc.sub() 这行代码会在编译时报错,因为 ploymophicBc 编译时类型为 BaseClass,而 BaseClass 中没有定义 sub 方法,因此编译时无法通过。
但是注意,ploymophicBc.book 的值为 6, 而不是 ”轻量级 Java EE“。因为对象的实例变量不具备多态性,系统总是试图访问它编译时类型所定义的成员变量,而非运行时。
小结
子类其实是一种特殊的父类,因此 java 允许把父类的引用指向子类对象,这被称为向上转型(upcasting),向上转型由系统自动完成。
可以调用哪些方法,取决于引用类型(编译时)。
具体调用哪个方法,取决于引用指向的实例对象(运行时)。
向下类型转换
问题:引用变量在代码编译过程中,只能调用它编译时类型具备的方法,而不能调用它运行时类型具备的方法
解决:强制转换成运行时类型
方法:引用类型之间的转换只能在有继承关系的两个类型之间进行,否则编译出错。如果想把一个父类引用变量的编译时类型转换成子类类型,则这个引用变量的运行时类型得是子类类型,否则引发 ClassCastException 异常
示例代码:
1 | //创建子类对象 |
instanceof
为了解决强制类型转换,可能引发的 ClassCastException 异常,引入 instanceof 运算符。
instanceof 运算符的含义:用于判断左边的对象(运行时类型)是否是右边的类或者其子类、实现类的实例。如果是返回 true,否则返回 false。
在之前的代码中,强制类型转换前使用 instanceof 判断:
1 | if (anmial instanceof Cat) { |