Java多态
1、多态中涉及到的几个概念:
向上转型(upcasting): 子类型---->父类型
向下转型(downcasting): 父类型--->子类型
需要记忆:
无论是向上转型还是向下转型,两种类型之间必须有继承关系。没有继承关系,程序无法编译通过。
package Test10;
import Test09.Animal;
public class Test {
public static void main(String[] args) {
//定义一个动物对象
Animal a1= new Animal();
a1.move();
Cat c1 = new Cat();
c1.move();
c1.catMouse();
//向上转型
//a2应该是Cat类型,变成了Animal
Animal a2 = new Cat();
a2.move();
}
}
package Test10;
import Test09.Animal;
//猫类
public class Cat extends Animal {
public void move(){
System.out.println("猫在爬动!");
}
public void catchMouse(){
System.out.println("猫在抓老鼠!");
}
}
//分隔符。。。。。。。。。。。。。。。。。。。。
```java
package Test10;
public class Animal {
public void move(){
System.out.println("动物在移动!");
}
}
上面代码创建了Animal类、Cat类,并在Test10中创建对象调用move方法。
在a2对象的创建中,是用了多态机制:Animal a2 =new Cat();
2、说明:
1、Animal和Cat之间存在继承关系,Animal是父类,Cat是子类。
2、new Cat() 创建的对象的类型是Cat,a2这个引用数据类型是Animal,显然他们进行了类型转换
子类型转换成了父类型,称为向上转型/upcasting
3、Java中允许出现这样的语法:父类型的引用指向子类型的对象
4、输出结果为“猫在爬动”。执行的是Cat类中方法覆盖之后的move方法。
5、如果a2调用catchMouce()会报错,因为Animal类中找不到catchMouce这个方法。
3、为什么无法调用catchMouse方法?:
1、java程序分为编译阶段和运行阶段。
2、如果编译阶段无法通过,运行阶段将不发生。
3、编译阶段编译器检查a2这个引用的数据类型是Animal,由于Animal.class字节码中有move()方法,所以编译通过了。这个过程称为静态绑定,编译阶段绑定。只有静态绑定成功之后才会有运行阶段。
4、在运行阶段,JVM堆内存中真实创建的对象是Cat对象,那么以下程序在运行阶段一定会调用Cat对象的move()方法,此时发生了动态绑定,运行阶段绑定。
问:如果把Cat类中方法覆盖的部分注释 ,那么它调用的move方法是哪里的?输出结果是什么?
它会调用Cat的从父类那里继承的move方法,结果为动物在移动
5、无论是Cat类有没有重写move方法,运行阶段一定会调用Cat对象的move方法,因为底层真实对象就是Cat对象。
6、父类型引用指向子类型对象这种机制导致了程序存在编译阶段绑定和运行阶段绑定两种不同的状态。
4、如果我们想调用a2.catMoucse?
a2是无法直接调用catchMouse方法的,因为a2的类型是Animal,Animal中没有catchMouse方法。
我们可以把a2强制转换为Cat类型。
a2的类型是Animal(父类),转换成Cat(子类),被称为向下转型。
注意:向下类型也需要两种类型之间必须有继承关系。
强制类型转换需要加强制类型转换符。
那么什么时候需要使用向下转型呢?
当调用的方法是子类型中特有的,在父类型中不存在,可以向下转型。
Animal a2 = new Cat();
a2.move();
Cat c2 = (Cat)a2;
c2.catMouse();
5、java.lang.ClassCastException异常
1、异常出现的状况
//定义一个Bird类,Bird类是Animal的子类,但是和Cat没有父子类的关系
Animal a3 = new Bird();
Cat c3 = (Cat)a3;
//报错:java.lang.ClassCastException异常
2、上面程序编译是没有问题的,因为编译器检查到a3的数据类型是Animal,Animal和Cat之间存在继承关系,并且Animal是父类型,Cat是子类型,父类型转换为子类型叫做向下转型,语法合格。
3、程序虽然编译通过了,但是程序在运行阶段会出现异常,因为JVM堆内存中真实存在的对象是Bird类型,Bird类型是无法转换成Cat类型的,两种类型之间是不存在继承关系的,此时会出现著名的异常:java.lang.ClassCastException
类型转换异常,这种异常总是在“向下转型”的时候出现。
6、怎么避免转型出现ClassCastException?
1、使用instanceof运算符可以避免以上的异常
2、怎么使用instanceof运算符来避免出现上述异常?
2.1 语法格式:
(引用 instanceof 数据类型名)
2.2 instanceof执行的结果是布尔类型
例如:(a instanceof Animal)
true:a这个引用指向的对象是Animal类型
false:a这个引用指向的对象不是Animal类型
3、修改之后的代码:
Animal a3 = new Bird();
if(a3 instanceof Cat){
Cat c3 = (Cat)a3;
}else{
Bird b2 = (Bird)a3;
}
7、多态的作用
面对对象编程的核心是:定义好类,然后将类实例化为对象,给一个环境驱使一下,让各个对象之间协作起来组成一个系统。
多态的作用是:
降低程序的耦合度,提高程序的扩展力。