多态

多态

多态是指用同样的对象调用同样的方法,但是做了不同的事情。即同一个接口,使用不同的实例而执行不同操作。

多态是一种思想方法,从语法层次上的体现形式为:
1)向上转型
2)动态绑定
3)方法覆写(override)override
1. 向上转型

表示父类和子类的类型转换。
向上转型常见的三种体现形式:

  • 直接赋值
  • 作为方法的参数
  • 作为方法的返回值

一个子类的对象,可以使用一个父类的引用去表示。

1)直接赋值
Animal bird = new Bird("圆圆");
2)作为方法的参数
public class Test {
    public static void main(String[] args) {
        Bird bird = new Bird("圆圆");
        feed(bird);
    }
    public static void feed(Animal animal) {
        animal.eat("谷子");
    }
}

此时形参 animal 的类型是 Animal (基类), 实际上对应到 Bird (父类) 的实例。

3)作为方法的返回值
public class Test {
    public static void main(String[] args) {
        Animal animal = findMyAnimal();
    }
    public static Animal findMyAnimal() {
        Bird bird = new Bird("圆圆");
        return bird;
    }
}

此时,方法 findMyAnimal 返回的是一个 Animal 类型的引用,但是实际上对应的是 Bird 的实例。

2. 动态绑定

此处的动态,指的是程序运行时,而不是编译时。

Animal.java
public class Animal {
    protected String name;
    public Animal(String name) {
        this.name = name;
    }
    public void eat(String food) {
        System.out.println("我是一只小动物");
        System.out.println(name + "正在吃" + food);
    }
}
Bird.java
public class Bird extends Animal {
    public Bird(String name) {
        super(name);
    }
    public void eat(String food) {
        System.out.println("我是一只小鸟");
        System.out.println(this.name + "正在吃" + food);
    }
}
Test.java
public class Test {
    public static void main(String[] args) {
        Animal animal1 = new Animal("圆圆");
        animal1.eat("谷子");
        Animal animal2 = new Bird("圆圆");
        animal2.eat("谷子")}
}
执行结果

在这里插入图片描述
animal1 和 animal2 虽然都是 Animal 类型的引用, 但是 animal1 指向 Animal 类型的实例, animal2 指向 Bird 类型的实例.。
针对 animal1 和 animal2 分别调用 eat 方法, 发现 animal1.eat() 实际调用了父类的方法, 而 animal2.eat() 实际调用了子类的方法。

父类和子类可能会包含名字相同,逻辑不同的方法。调用这个方法时,到底是执行父类的方法还是子类的方法,是在程序运行过程中确定的,而不是编译过程中确定的。

3. 方法覆写

子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override)。此处指运行时的多态。

方法覆写的规则:
  • 1)方法名相同
  • 2)参数完全相同(个数和类型都相同)
  • 3)返回值相同
  • 4)子类的方法访问权限不能低于父类的访问权限
@Override功能有两个方面:
  • 1)让代码读者更清楚的理解这个方法是要重写的
  • 2)做出一些编译的检查,万一手误写错了参数,这时没有按照预期构成重写,编译就能检查出来

普通方法可以重写, static 修饰的静态方法不能重写。

使用多态
(类的实现者)
public class Shape {
    public void draw();
}

public class Circle extends Shape {
    @Override
    public void draw() {
        //绘制一个圆
        System.out.println("○");
    }
}

public class Rect extends Shape {
    @Override
    public void draw() {
        System.out.println("□");
    }
}

public class Flower extends Shape {
    @Override
    public void draw() {
        System.out.println("❀");
    }
}
Test.java (类的调用者)
public class Test {
    public static void main(String[] args) {
        Shape s1 = new Circle();
        Shape s2 = new Rect();
        Shape s3 = new Flower();

        drawShape(s1);
        drawShape(s2);
        drawShape(s3);
    }
    public static void drawShape(Shape s) {
        s.draw();
    }
}

当类的调用者在编写 drawShape 这个方法的时候, 参数类型为 Shape (父类), 此时在该方法内部并不知道, 也不关注当前的 shape 引用指向的是哪个类型(哪个子类)的实例. 此时 shape 这个引用调用 draw 方法可能会有多种不同的表现 (和 shape 对应的实例相关), 这种行为就称为多态。
多态是封装的更近一步:

  • 封装是为了让类的调用者不需要知道类的实现细节(还是得知道这个类是什么类)
  • 多态这里类的调用者都不需要知道这个类是什么类型,只需要知道这个类有一个draw方法就可以了
多态总结

使用多态好处:

  • 类调用者对类的使用成本进一步降低
  • 能够降低代码的“圈复杂度”,避免使用大量的“if - else”
    • “圈复杂度”指的是一段代码的复杂程度,通常计算为代码中分支 / 循环语句中的个数。
    • 如果一 个方法的圈复杂度太高, 就需要考虑重构。
  • 如果要新增一种新的形状, 使用多态的方式代码改动成本也比较低。
    • 举例:
class Triangle extends Shape {
    @Override 
    public void draw() {
        System.out.println("△"); 
    }
}

对于类的调用者来说(drawShape方法), 只要创建一个新类的实例就可以了, 改动成本很低。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值