向上转型、向下转型
向上转型:子—》父,(也叫做自动类型转换)
向下转型:父—》子,(也叫做强制类型转换,需要加强制类型转换)
注意:工作的时候不要说自动/强制类型转换,因为这些术语用于基本数据类型而不是引用数据类型
不管是向上转型还是向下转型,都有一个大前提:它们之间存在继承关系
public class Test01{
public static void main(String [] args){
Animal a1=new Animal();
a1.move();
Cat c=new Cat();
c.move();
Birde b=new Birde();
b.move();
Animal a2=new Cat();//向上转型,子类转为父类
Animal a3=new Birde();//向下转型,父类转为子类
//Java允许向上和向下转型,无论向上还是向下转型,两种类型之间必须存在继承关系,没有继承关系的不能转型
a2.move();//猫走猫步
a3.move();//鸟儿在飞翔
/*Animal a4=new dog();
a4.move();
错误: 不兼容的类型: dog无法转换为Animal
*/
}
}
a2.CatchMouse();//不能通过编译,因为编译的时候,编译器只知道a2的类型是Animal类里并没有Catchmouse方法。
结果没有找到,所以静态绑定失败,编译报错,无法运行
*/
假设代码写到这里非要调用CatchMouse(),这个时候就要向下转型(什么时候向下转型?访问子类里特有的方法)
Cat c2=(Cat) a2;//向下转型,访问特定的方法。因为存在继承关系,所以没有报错
/*dog d1=new dog();
Cat c3=(Cat)d1;错误: 不兼容的类型: dog无法转换为Cat
*/
c2.CatchMouse();//猫在抓老鼠
下面这段语句编译没问题,运行时报错:ClassCastException**(这个异常和空指针异常一样特别重要)**
因为在运行时堆内存实际创建的对象时:Birde对象。运行过程中拿着Birde对象转换成Cat对象这是不行的,因为它们之间没有继承关系
Animal a4=new Birde();
Cat y=(Cat)a4;
y.CatchMouse();
向下转型时怎么避免ClassCastException异常的发生?
以后只要用到向下转型就要进行这样的判断
Animal a4=new Birde();//a4 指向的堆内存是Birde
if(a4 instanceof Cat){
Cat y=(Cat)a4;
y.CatchMouse();
}
运算符:instanceof
第一、instanceof可以在运行阶段动态判断引用指向对象的类型
第二、instanceof的语法:
(引用 instanceof 类型)
第三、instanceof运算符的运算结果只能是:true/false
第四、c是一个引用,c变量保存了内存地址,指向了堆中的对象
假设(c instanceof Cat)为true表示:c引用指向的堆内存中的java对象是一个Cat
假设(c instanceof Cat)为false表示:c引用指向的堆内存中的java对象不是一个Cat
多态
多态指的是多种形态:编译的时候一种形态,运行的时候一种形态
多态就是父类型引用指向子类型对象
java程序分为编译阶段和运行阶段。
先来分析编译阶段:
对于编译器来说,编译器只知道a2的类型是Animal,所以编译器在检查语法的时候,会去Animal.class字节码文件中找mov()方法(并不会new对象),找到了并且绑定上move()方法,编译通过,静态绑定成功(编译阶段属于静态绑定)
再来分析运行阶段:
运行阶段的时候,实际上在堆内存中创建的java对象是Cat对象,所以move的时候,真正参与move的对象是一只猫,所以运行阶段会动态执行Cat对象的move方法,这个过程属于运行阶段绑定(运行阶段绑定属于动态绑定)