多态
Java中的多态可以用一句话来概括:
父类引用指向子类对象
从这句话可以看出,有三个关键的点:
父类引用、指向关系、子类对象
在理解这句话之前,我们先来学习两个概念:向上转型和向下转型
注意:无论是向上转型还是向下转型,两个类之间都必须要有继承关系
向上转型
什么是向上转型呢,这里先用一段代码来演示一下:
class Test{
public static void main(String[] args) {
//向上转型
Animal a = new Cat();
a.move();
}
}
public class Animal {
public void move(){
System.out.println("动物在移动");
}
}
class Cat extends Animal{
public void move(){
System.out.println("猫咪在移动");
}
}
这里,我们定义了一个Animal类,里面有一个move方法,还有一个Cat类,继承自Animal类,并且重写了Animal类的move方法,在主方法中,使用
new Cat()创建了一个Cat对象,但是在等号左边我们声明的类型却是Animal,这里就用到了向上转型。实际上这里的new Cat()创建出来的对象底层还是Cat类型,只不过这里我们用父类引用去指向了该对象。
因为Cat是继承自Animal类的,我们可以用 is a 的关系来描述 Cat和Animal,也就是Cat is a Animal,Cat类是子类,Animal是父类。像这种用父类的引用来指向子类对象的操作就称为向上转型
向下转型
从上面的向上转型我们可以得出结论,子类到父类的称为向上转型,那么父类到子类就称为向下转型。
还是用一段代码来演示一下:
class Test{
public static void main(String[] args) {
Animal a = new Cat();
a.move();
//a.CatchMouse();
Cat cat = (Cat)a;
cat.CatchMouse();
}
}
public class Animal {
public void move(){
System.out.println("动物在移动");
}
}
class Cat extends Animal{
public void move(){
System.out.println("猫咪在移动");
}
public void CatchMouse(){
System.out.println("猫咪可以抓老鼠");
}
}
还是和上面代码类似,只不过这次在Cat类中添加了一个CatchMouse()方法。这个方法是Cat类独有的,我们通过父类引用a不能访问到。
这个时候就需要用到向下转型。
首先,还是用刚才声明的a变量,只不过这一次我们需要在a变量前加上强制类型转换,也就是
Cat cat = (Cat)a;
这个括号中的Cat就是把刚才声明的父类引用转换成Cat对象。接下来就可以拿着转换后的对象,也就是cat对象去访问子类中的CatchMouse方法了。
总结:什么时候需要用到向下转型呢?
当我们想要访问子类中特有的方法的时候,就要用到向下转型(也叫强制类型转换)
但是,强制类型转换是有风险的
例如,下面这个代码:
Animal animal = new Dog();
Cat cat = (Cat)animal;
cat.CatchMouse();
这里我们还采用父类引用指向子类对象的操作,将一个底层是Dog类型的对象向上转为Animal类型。然后我们将这个底层是Dog类型的对象转为Cat类型,编译的时候并不会报错。然后接下来去调用Cat类的特有方法CatchMouse,但是运行的时候却出现了 ClassCastException异常,也就是类型转换异常。
为什么会出现这个错误呢?
原因在于:
编译阶段,编译器检测到animal这个引用是Animal类型,而Animal和Cat之间存在继承关系,所以可以向下转型,这个时候编译器是可以通过的
运行阶段,堆内存实际创建的对象是:Dog对象。在实际运行过程中,拿着Dog对象转换成Cat对象就不行了。因为Dog和Cat之间没有继承关系
解决办法:使用 instanceof 关键字
当我们需要使用向上转型的时候,使用 instanceof关键字对类型先进行判断,然后再去执行相关语句,这样就保险了。
未完待续…