多态
生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。
定义
多态是指同一行为,具有多个不同的表现形式
前提
- 继承或者实现
- 方法的重写
- 父类引用指向子类对象【格式体现】
体现
格式
父类类型 变量名 = new 子类对象;
变量名.方法名();
父类类型:指子类对象继承的父类类型,或者实现的父接口类型
例:
Fu f = new Zi();
f.method();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译出错;如果有,执行的是子类重写后的方法
多态的好处
实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。
引用类型转型
向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。
向上转型一定是向上转型一定是安全的,没有问题的,
但是对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。解决方案:用对象的向下转型
父类类型 变量名 = new 子类类型(); 如: Animal = new Cat();
向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。
子类类型 变量名 = (子类类型) 父类变量名; Cat c = (Cat) animal;
为什么要转型
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。这也是多态给我们带来的一点”小麻烦”。所以,想要调用子类特有的方法,必须做向下转型。
定义类:
public abstract class Animal {
abstract void eat();
}
public class Cat extends Animal {
@Override
void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
定义测试类:
public class Demo01Main {
public static void main(String[] args) {
// 对象的向上转型,就是父类引用指向子类对象
Animal animal = new Cat();// 创建的时候是一只猫
animal.eat();
// animal.catchMouse();// 错误
// 向下转型,进行“还原”动作
Cat cat = (Cat) animal;
cat.catchMouse();
// 下面是错误的向下转型
// 本来new的是一只猫,现在非要当做狗
// 编译通过,但是运行会出现异常
// Dog dog = (Dog) animal; // java.lang.ClassCastException,类转换异常
}
}
转型的异常
public class Test{
public static void main(String[] args) {
//向上转型
Animal a = new Cat();
a.eat();//调用的是Cat的eat
//向下转型
Dog d = (Dog) a;
d.watchHouse();//调用的是Dog的watchHouse【运行报错】
}
}
这段代码可以通过编译,但是运行时会ClassCastException
,类型转换异常,这是因为创建的 Cat 类型对象无法转换成 Dog 类型的对象
为避免这样的问题,java 提供了instanceof
关键字,给引用变量做类型的检验
变量名 instanceof 数据类型
如果变量属于该数据类型,返回true。
如果变量不属于该数据类型,返回false。
所以转换前,我们最好先做一个判断,代码如下
public class Test {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();//
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.watchHouse();
}else if (animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.catchMouse();
}
}
}