1. 无论向上转型还是向下转型,都需要有继承关系,否则编译器报错!
向上转型:子类型转向父类(自动类型转换)
向下转型:父类型转向子类(强制类型转换,需要加强制类型转换符)
2. 什么是多态?
多态是同一个行为具有多个不同表现状态的能力。
多种状态,编译时是一种状态,运行时是另一种状态。
编译时,是静态绑定。编译器去找父类Animal中的move()方法,找到了,则编译通过,静态绑定成功;
运行时,是动态绑定。由于实际在堆内存中创建的对象是Cat对象,所以实际执行时会动态执行Cat的move()方法。(动态绑定是Java的默认行为,相当于C++的虚函数)
上述过程,就是父类型引用指向子类型对象,向上转型,产生了多种形态(编译阶段绑定父类,运行阶段绑定子类)。
注:如果调用的是子类独有的方法,比如catch(),则不会通过编译,因为无法在父类中找到该方法。
3. 什么时候必须使用向下转型?
想要调用的方法是子类特有的,则需要强制类型转换(向下转型)。
向下转型有风险!如果失败,会抛出java.lang.ClassCastException;
比如堆内存中创建的是Bird对象,用父类Animal类型引用a1接收,此时执行向下转型到Cat,会出错。
Animal a1=new Bird(); Cat c1=(Cat)a1;//出错
避免异常发生?使用instanceof来判断一个对象是不是属于该类型(运行阶段动态判断)
if(a1 instanceof Cat){//返回true或false Cat c1=(Cat)a1; }
所以每当向下转型时,都要用instanceof进行类型判断,来避免ClassCastException。
4. JVM中多态运行情况
当执行 invokevirtual 指令(JVM方法调用指令,用于调用对象的实例方法)时,
(1) 先通过栈帧中的对象引用找到对象
(2) 分析对象头,找到对象的实际 Class
(3) Class 结构中有 vtable(标明这个类有几个方法),它在类加载的链接阶段就已经根据方法的重写规则生成好了
(4) 查表得到方法的具体地址
(5) 执行方法的字节码