Java-多态

156 阅读3分钟

1、多态能解决什么问题?

问题:可以确定某个变量、元素等它的类型是属于某个系列的,但是不能确定它更具体的类型。
这个变量需要赋值的对象可能是这个系列的子类的任意一种对象。
那么就需要多态这种特性支持。

场景1:同一个数组希望它既可以存储学生对象、教师对象、其他员工对象
场景2:给某个类设计成员变量时,只知道它属于某个系列的类型,但是具体是哪个类型不清楚

class Husband{//Husband丈夫
    private String name;
    private Wife lover ;
}

Wife的类型可以是一个Person,Robot(机器人),Demon(妖)

场景3:在设计一个方法的形参、返回值类型时,可以确定它是某个系列的类型,但是不能确定具体是哪个类型

public void compareArea(图形类型 g1, 图形类型  g2)
图形类型:可能是矩形、圆、三角形...

2、什么是多态?

(1)多态引用的概念
父类类型 变量 = 子类的对象;

父类类型:指子类继承的父类类型,或者实现的父接口类型。

所以说继承是多态的前提

(2)多态的现象
编译时类型和运行时类型不一致。
表现:编译时类型与运行时类型不一致,编译时看“父类”,运行时看“子类”。

子类重写了父类的方法,通过父类的变量调用重写的方法时,执行的是子类重写后的代码。
子类如果没有重写这个方法,还是执行父类中实现的方法体。

对象的本质类型是子类的类型,只是编译器在编译时,把它看成父类的类型,把它当成父类的类型来“检查”
父类类型 变量 = 子类的对象;
编译时:这个变量是"父类"类型,也只能调用父类中的方法。
运行时:这个变量是子类的类型,所以他会执行子类重写的方法体

3、应用的场景

(1)多态数组
元素的类型声明为父类的类型,元素实际存储的是子类对象
(2)多态参数
形参的类型是父类的类型,实参对象是子类对象
(3)多态返回值
方法的返回值类型写的是父类类型,实际返回的是子类对象
(4)变量的类型是父类的类型,变量的值是子类的对象

编译时看父类,运行时看子类。“重写的方法”

4、多态演示

让Dog和Cat都继承Pet宠物类。

public class Cat extends Pet {
    //子类重写父类的方法
    @Override
    public void eat() {
        System.out.println("猫咪" + getNickname() + "吃鱼仔");
    }
    
    //子类扩展的方法
    public void catchMouse() {
        System.out.println("抓老鼠");
    }
}
public class Dog extends Pet {
    //子类重写父类的方法
    @Override
    public void eat() {
        System.out.println("狗狗" + getNickname() + "啃骨头");
    }

    //子类扩展的方法
    public void watchHouse() {
        System.out.println("看家");
    }
}
public class Pet {
    private String nickname;
    
    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public void eat(){
        System.out.println(nickname + "吃东西");
    }
}
public class TestPet {
    public static void main(String[] args) {
        //多态引用
        Pet pet = new Dog();
        pet.setNickname("小白");

        //多态的表现形式
        /*
        编译时看父类:只能调用父类声明的方法,不能调用子类扩展的方法;
        运行时,看“子类”,如果子类重写了方法,一定是执行子类重写的方法体;
         */
        pet.eat();//运行时执行子类Dog重写的方法
         //狗狗小白啃骨头
         //pet.watchHouse();//不能调用Dog子类扩展的方法

        pet = new Cat();
        pet.setNickname("雪球");
        pet.eat();//运行时执行子类Cat重写的方法
        //猫咪雪球吃鱼仔
    }
}

多态调用方法分析: 多态调用方法分析.png