1、什么是多态
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
通俗点讲,多态就是不同对象对同一物体或事件发出不同的反应或响应。比如stuendt是一个父类,那么在操场上上体育课的学生和在教室里面的学生就是它的子类。这时上课铃声响了,上体育课的学生去操场,在教室里面上课的学生则是回教室,不同的学生有着不同的反应,这就是多态。
可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
比如,你的女盆友让你买点水果回来,不管买回来的是苹果还是西瓜,只要是水果就行,这个就是生活中多态的体现
再比如,小猫、小狗、小猪我们可以把他们都归纳成小动物,每种小动物都需要吃东西,所以我们可以统一设置他们都必须吃,但是每种小动物的习性不一样,那这个就可以设置成小动物自己特有的功能,多态对象只能调用父类中定义子类中重写的功能,并不能调用子类的特有功能,这样就实现了代码的统一。
2.多态的体现形式
在java中多态可以体现在方法上比如方法的重载,同名方法可以有不同的执行结果。多态也可以体现在面向对象中,一个对象可以使用多种类型进行表示。
2.1方法层面的多态:就是方法重载(这里我们就不加以赘述)
2.2面向对象层面的多态:把子类对象赋给父类的类型
父类类型 子类对象的名字=new 子类构造方法();
A b =new a(); (a是A的子类)
这也就是多态的想上转型!
将a类型的对象由他的父类类型A来接收。
那么向上转型的作用是什么呢?
在上面我们说了子类需要对父类中的一些方法进行重写,然后调用方法时就会调用子类重写的方法而不是原本父类的方法。向上转型后,子类单独定义的方法会丢失(即子类重载了父类中的方法),而子类中重写了父类的方法,当我们调用他们时,会调用重写的方法。理解起来麻烦的话,直接来看代码吧。
public class TestDemo {
public static void main(String[] args) {
//6.创建“纯纯的”对象用于测试
Animal a = new Animal();
Cat c = new Cat();
Dog d = new Dog();
a.eat();//小动物Animal吃啥都行~调用的是父类自己的功能
c.eat();//小猫爱吃小鱼干~调用的是子类重写后的功能
d.eat();//小狗爱吃肉骨头~调用的是子类重写后的功能
/*2.父类对象不可以使用子类的特有功能*/
//a.jump();//报错,Animal类里并没有这个方法
//a.run();//报错,Animal类里并没有这个方法
c.jump();//小猫Cat跳的老高啦~,子类可以调用自己的功能
d.run();//小狗Dog跑的老快啦~,子类可以调用自己的功能
//7.创建多态对象进行测试
/*3.口诀1:父类引用指向子类对象
* 解释:创建出来的子类对象的地址值,交给父类类型的引用类型变量来保存*/
Animal a2 = new Cat();//Cat类对象的地址值交给父类型变量a2来保存
Animal a3 = new Dog();//Dog类对象的地址值交给父类型变量a3来保存
//8.测试多态对象
/*4.口诀2:编译看左边,运行看右边
* 解释:必须要在父类定义这个方法,才能通过编译,把多态对象看作是父类类型
* 必须要在子类重写这个方法,才能满足多态,实际干活的是子类*/
a2.eat();//小猫爱吃小鱼干~,多态对象使用的是父类的定义,子类的方法体
}
}
/*1.多态的前提:继承+重写*/
//1.创建父类
class Animal{
//3.创建父类的普通方法
public void eat(){
System.out.println("小动物Animal吃啥都行~");
}
}
//2.1创建子类1
class Cat extends Animal{
//4.1添加重写的方法
public void eat(){
System.out.println("小猫爱吃小鱼干~");
}
//5.1添加子类的特有功能
public void jump(){
System.out.println("小猫Cat跳的老高啦~");
}
}
//2.2创建子类2
class Dog extends Animal{
//4.2添加重写的方法
@Override
public void eat(){
System.out.println("小狗爱吃肉骨头~");
}
//5.2添加子类的特有功能
public void run(){
System.out.println("小狗Dog跑的老快啦~");
}
}
既然我们有向上转型,那么不可避免的我们就一定能向下转型!(但是在我们的实际运用中,向下转型一般很少使用)
向下转型:子类的引用的指向子类对象,过程中必须要采取到强制转型。这个是之前向上造型过的子类对象仍然想执行子类的特有功能,所以需要重新恢复成子类对象
Parent p = new Child();//向上转型,此时,p是Parent类型
Child c = (Child)p;//此时,把Parent类型的p转成小类型Child
其实,相当于创建了一个子类对象一样,可以用父类的,也可以用自己的
说明:向下转型时,是为了方便使用子类的特殊方法,也就是说当子类方法做了功能拓展,就可以直接使用子类功能。
比如:花木兰打仗结束,就不需要再看做是她爸了,就可以”对镜贴花黄”了
注意:在多态中,在其成员的调用上
调用成员属性:编译看左边,运行看左边
调用成员方法:编译看左边,运行看右边
3、那么我们在什么时候用多态呢
在继承关系中,当多个子类有相同的行为时,调用者并不确定具体的对象,此时我们可以使用多态来解决。
动物类下面的子类 猫跟狗,猫跟狗都有吃饭的方法;
但是如果有一个调用者来调用吃饭的方法,那么它调用的是猫类的吃饭方法还是狗类的吃饭方法呢?
就不能确定,因此我们使用多态,(对象的多种形态),把父类的类型当成参数来解决这个问题。
public class Animal {
String name="父类";
public void run(){
System.out.println("这是父类中的跑的方法");
}
}
public class Cat extends Animal {
String name="小花猫";
public void run(){
System.out.println("这是猫类里面的跑方法");
}
public void zhui(){
System.out.println("猫追蝴蝶");
}
}
public class Dog extends Animal {
String name="旺财";
public void run(){
System.out.println("这是狗类的跑方法");
}
public void catchMouse(){
System.out.println("狗拿耗子");
}
}
public class Test {
public static void main(String[] args) {
public static void eat(Animal animal){
Cat cat=(Cat)animal;
cat.zhui();
if(animal instanceof Cat){
System.out.println("猫吃鱼");
animal.run();
((Cat) animal).zhui();
}else if(animal instanceof Dog){
System.out.println("狗吃骨头");
animal.run();
((Dog) animal).catchMouse();
}
}
4、多态的好处
- 多态可以让我们不用关心某个对象到底具体是什么类型,就可以使用该对象的某些方法
- 提高了程序的可扩展性和可维护性