多态是继封装、继承之后面向对象的第三大特性。
多态也即是同一行为多个不同的表现形式
前提
- 继承或者实现
- 方法的重写
- 父类引用指向子类对象
多态体现的格式
父类类型 变量名 = new 子类类型();
变量名.方法名();
父类类型:即子类对象继承的父类类型或者实现的接口类型
代码举例:
Fu f = new Zi();
f.method();
当使用多态的方式来调用方式时,首先会检查父类中是否含有该方法,若没有就会产生编译错误;若有,就会执行子类覆盖重写的方法
代码举例:
定义父类:
public abstract class Animal{
public abstract void eat();
}
定义子类
public class Cat extends Animal{
public void eat(){
System.out.println("吃鱼");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("吃肉骨头");
}
}
定义测试类
public class Test{
public static void main(String[] args){
//多态形式创建对象
Animal cat = new Cat();
//调用Cat类中eat()方法,输出吃鱼
cat.eat();
Animal dog = new Dog();
//调用Dog类中eat()方法,输出吃肉骨头
dog.eat();
}
}
多态优点
在实际开发中,使用父类类型作为方法的形式参数,然后传递子类对象给方法,供方法调用能够体现出多态的扩展性和便利性,代码举例
定义父类
public abstract class Animal{
public abstract void eat();
}
定义子类
public class Cat extends Animal{
public void eat(){
System.out.println("吃鱼");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("吃肉骨头");
}
}
定义测试类
public class Test{
public static void main(String[] args){
Cat cat = new Cat();
Dog dog = new Dog();
showCatEat(cat);
showDogEat(dog);
//以上两个方法均可以被showAnimalEat(Animal a)所取代,同时机型效果一致
showAnimalEat(cat);
showAnimalEat(dog);
}
public static void showCatEat(Cat cat){
cat.eat();
}
public static void showDogEat(Dog dog){
dog.eat();
}
public static void showAnimalEat(Animal a){
a.eat();
}
}
在多态特性的支持下,showAnimalEat方法中的参数可以接受Animal的子类对象,而当方法执行时,会执行子类覆盖重写的方法,所以即便此后出现更多子类,showAnimalEat也可以完全替代
多态使得程序编写更加简单,并且获得良好的扩展
引用类型转换
多态的转型可分为向上转型和向下转型两种
向上转型:子类类型向父类类型转化的过程,此过程一般时默认的
当父类引用指向一个子类对象时,便是向上转型
格式
父类类型 变量名 = new 子类类型();
如:Animal a = new Cat();
向下转型:父类类型向子类类型转化的过程必须强制进行
一个已经向上转型的子类对象,将父类引用转化为子类引用,可以用强制类型转化的格式,即是向下转型
格式
子类类型 变量名 = (子类类型) 父类变量名;
如:Cat c = (Cat) a;
为什么要进行转型
当使用多态方式调用方法时,首先会检查父类中是否含有该方法,若没有,则会产生编译错误。也即是说,无法调用子类特有的而父类不存在的方法,若果想要调用子类特有方法,则必须向下转型
例
定义类
public abstract class Animal{
public abstract void eat();
}
public class Cat extends Animal{
public void eat(){
System.out.println("吃鱼");
}
public void catchMouse(){
System.out.println("抓老鼠");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("吃骨头");
}
public void watchHouse(){
System.out.println("看家");
}
}
定义测试类
public class Test{
public static void main(String[] args){
Animal a = new Cat(); //向上转型
a.eat(); //调用了Cat中的eat
Cat c = (Cat) a; //向下转型
c.catchMouse(); //调用了Cat中的catchMouse
}
}
转型异常
例
public class Test{
public static void main(String[] args){
Animal a = new Cat(); //向上转型
a.eat(); //调用了Cat中的eat
Dog d = (Dog) a; //向下转型
d.watchHouse(); //运行报错
}
}
这段代码能够通过编译,但是运行时会爆出ClassCastException,类型转换异常,因为创建的是Cat类型对象不能转化为没有继承关系的Dog对象,不符合类型转换定义
为了避免ClassCastException,可以通过instanceof检验
变量名 instanceof 数据类型
如果变量属于该类型,返回true
反之返回false
所以在转换前最好做一个判断
public class Test{
public static void main(String[] args){
Animal a = new Cat(); //向上转型
a.eat(); //调用了Cat中的eat
if (a instanceof Cat){
Cat c = (Cat) a;
c.catchMouse();
}else if (a instanceof Dog){
Dog d = (Dog) a;
d.watchHouse();
}
}
}
附一个多态面试题
class A {
public String show(D obj){
return ("A and D");
}
public String show(A obj){
return ("A and A");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{}
class D extends B{}
class DynamicTest
{
public static void main(String[] args){
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(b));
System.out.println(a1.show(c));
System.out.println(a1.show(d));
System.out.println(a2.show(b));
System.out.println(a2.show(c));
System.out.println(a2.show(d));
System.out.println(b.show(b));
System.out.println(b.show(c));
System.out.println(b.show(d));
}
}