1.概述
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
多态性是对象多种表现形式的体现😊
多态的优点:
消除类型之间的耦合关系
可替换性
可扩充性
接口性
灵活性
简化性
多态存在的三个必要条件:
继承
重写
父类引用指向子类对象:Parent p = new Child();
左父右子是多态👀
2.方法的多态
重载性质的多态
传入不同的参数,就会调用不同的方法,实现多态🎁
class B { } class A extends B { public int sum(int n1, int n2) { return n1 + n2; } public int sum(int n1, int n2, int n3) { return n1 + n2 + n3; } }
测试类:
A a = new A(); // 这里我们传入不同的参数,就会调用不同的sum方法,实现多态 System.out.println(a.sum(10, 20)); System.out.println(a.sum(10, 20, 30));
重写性质的多态
调用重名方法,但是结果不同,实现多态🎈
class B { public void say() { System.out.println("B类的say方法被调用"); } } class A extends B { public void say() { System.out.println("A类的say方法被调用"); } }
测试类:
A a = new A(); B b = new B(); // 虽然调用的都是say方法,但是结果不同,实现多态 a.say(); b.say();
3.对象的多态
一个对象的编译类型可以和运行类型不一样👀
Animal animal = new Dog(); // 子类的对象使用父类的引用
此时,我们说编译类型是Animal,运行类型是Dog
编译类型在定义对象时就确定了,不能改变❌运行类型是可以变化的👨
Animal animal = new Dog(); // 子类的对象使用父类的引用,此时运行类型为🐕 animal = new Cat(); // 改变运行类型,改为🐱
编译类型看定义时候 = 的左边,运行类型看 = 的右边😁
4.对象多态的使用
运行的内容要看运行类型
父类:
/** * 对象多态的父类 */ public class ObjectPolymorphicAnimal { public void cry() { System.out.println("Animal的cry被调用!"); } }
子类:
/** * 对象多态的子类 - 🐕 */ public class ObjectPolymorphicDog extends ObjectPolymorphicAnimal{ public void cry() { System.out.println("汪汪汪!"); } }
测试类:
/** * 对象多态的测试类 */ public class ObjectPolymorphicTest { public static void main(String[] args) { ObjectPolymorphicAnimal opa = new ObjectPolymorphicDog(); opa.cry(); // 汪汪汪! } } ----------------------------- 由于运行类型是Dog类,所以会执行Dog类的cry方法
改变运行类型
针对上面的程序,我们再写一个🐱类子类:
/** * 对象多态的子类 - 🐱 */ public class ObjectPolymorphicCat extends ObjectPolymorphicAnimal{ public void cry() { System.out.println("喵喵喵~"); } }
测试类:
// 改变引用的运行类型 opa = new ObjectPolymorphicCat(); opa.cry(); // 喵喵喵~
以上就演示了对象多态的基本入门🚀
5.向上转型
父类类型 引用名 = new 子类类型();
切记,子类必须要重写父类的方法才能被使用,因为编译器编译阶段能调用那些成员是由编译类型决定的👌
而最终的运行效果要看子类(运行类型)的具体实现,即调用方法时,采取从子类开始的就近原则
总结一句话就是:
编译看编译类型(父类),运行看运行类型(子类)🚀
6.向下转型
子类类型 引用名 = (子类类型) 父类引用;
实例:
ObjectPolymorphicAnimal opa = new ObjectPolymorphicCat(); // 我们通过opa是无法访问Cat类没有被重写的方法的 // 那么此时希望调用cat的eatFish方法,采用向下转型 // 注意:向下转型有一个条件,就是父类的引用必须指向的是当前目标类型的对象 // 也就是opa的运行类型必须是ObjectPolymorphicCat! // 注意:此时的编译类型和运行类型都是ObjectPolymorphicCat // 类型的强制转换 ObjectPolymorphicCat cat = (ObjectPolymorphicCat) opa; cat.eatFish();
7.多态中的属性
多态中的属性没有重写一说,结果看编译类型🐱🏍
例如父类中有这样一个属性:
int year = 2022;
子类中也有这样一个属性:
int year = 2021;
下面的代码会输出2022:(因为编译类型是ObjectPolymorphicAnimal)
ObjectPolymorphicAnimal opa = new ObjectPolymorphicCat(); // 多态中的属性,看编译类型 System.out.println(opa.year);
8.instanceOf比较操作符
用于判断对象的运行类型是否为XX类型或者XX的子类型
示例:
ObjectPolymorphicAnimal opa = new ObjectPolymorphicCat(); // instanceOf比较操作符 System.out.println(opa instanceof ObjectPolymorphicCat); // true System.out.println(opa instanceof ObjectPolymorphicDog); // false System.out.println(opa instanceof ObjectPolymorphicAnimal); // true