多态是继封装、继承之后,面向对象的第三大特性,指的是一类事物的行为具有多种形态。
生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也 是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。
多态实现的前提:
Java代码中使用多态的格式:
父类类型 变量名 = new 子类对象; //父类类型:指子类对象继承的父类类型,或者实现的父接口类型。
变量名.方法名();
我们先定义一个父类
public abstract class Animal {
public abstract void eat();
}
然后定义两个子类实现父类的eat方法
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void watch() {
System.out.println("警戒中。。");
}
}
多态的测试使用
public static void main(String[] args) {
// 多态形式,创建对象
Animal a1 = new Cat();
// 调用的是 Cat 的 eat
a1.eat();
// 多态形式,创建对象
Animal a2 = new Dog();
// 调用的是 Dog 的 eat
a2.eat();
a2.watch(); // 编译报错
}
由输出结果可知,当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后的方法。
我们看下面的一个例子:
public static void main(String[] args) {
// 多态形式,创建对象
Cat c = new Cat();
Dog d = new Dog();
// 调用showCatEat
showCatEat(c);
// 调用showDogEat
showDogEat(d);
/*
以上两个方法, 均可以被showAnimalEat(Animal a)方法所替代
而执行效果一致
*/
showAnimalEat(c);
showAnimalEat(d);
}
public static void showCatEat (Cat c){
c.eat();
}
public static void showDogEat (Dog d){
d.eat();
}
public static void showAnimalEat (Animal a){
a.eat();
}
由上面的例子我们可以知道,当把父类类型作为方法形式参数,子类对象作为实际参数传递给方法,方法体内调用的是子类重写父类的那个方法(假如子类没有该方法,则调用父类本身的方法)。
利用多态的这个特性,不管Animal有多少个子类,只要该子类重写了父类的eat方法,都可以调用showAnimalEat方法来展示,而不需要每新增一个子类,都要创建一个showXXXEat方法。所以多态的好处就是可以使程序 编写更简单,更易于扩展。
在使用多态的过程中,我们常常会遇到下面代码所示的问题。
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Dog 的 eat
// 向下转型
Dog d = (Dog)a;// 运行时会报错
d.watch();
}
这段代码可以通过编译,但是运行时,却报出了 ClassCastException 类型转换异常!这是因为,我们虽然创建的是Cat类型对象,但是a属于父类Animal的引用,编译器编译时并不知道c的具体类型,所以编译时期强制转换成Dog时没有报错。而运行时,虚拟机已经识别出a是Cat对象,Cat和Dog这两个类型并没有任何继承关系,不符合类型转换的定义,此时强制转换自然会报ClassCastException 异常。
为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:
变量名 instanceof 数据类型
如果变量属于该数据类型,返回true。
如果变量不属于该数据类型,返回false。
所以,转换前,我们最好先做一个判断,代码如下:
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
if (a instanceof Cat){
Cat c = (Cat)a;
c.eat(); // 调用的是 Cat 的 eat
} else if (a instanceof Dog){
Dog d = (Dog)a;
d.watch(); // 调用的是 Dog 的 watch
}
}
原文:https://www.cnblogs.com/linfuxian/p/13921089.html