栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java 三大特性之多态

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java 三大特性之多态

目录

1. 多态实现的三个必要条件

1.1 继承

1.2 向上转型

1.2.1 向上转型发生的时机

1.3 重写

2. 理解多态(多态示例)

3. 使用多态的好处

3.1 类调用者对类的使用成本进一步降低

3.2 简化性

3.3 可扩展能力更强

4. 多态的实现方法

5. 向下转型


 

 多态是指同一个行为具有多个不同表现形式或形态的能力。

1. 多态实现的三个必要条件
  • 继承
  • 向上转型
  • 重写
1.1 继承

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。

1.2 向上转型

向上转型就是子类对象转换为父类的引用,是天然发生的。

代码示例:


class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat(String food) {
        System.out.println(this.name + "正在吃" + food);
    }
}

class Bird extends Animal {
    public Bird(String name) {
        super(name);
    }

    public void fly() {
        System.out.println(this.name + "正在飞 ");
    }
}

public class Demo2 {
    public static void main(String[] args) {
        // 创建一个动物类的对象
        Animal animal = new Animal("小动物");
        // 创建一个鸟类的对象
        Bird bird = new Bird("小鸟");

        // 向上转型
        Animal animal1 = new Bird("小鸟");
        System.out.println(animal.name);
        animal.eat("食物");

    }
}

 上面的代码中,我们有这样的代码:

Bird bird = new Bird("小鸟");

这个代码也可以这样写:

Bird bird = new Bird("小鸟");
Animal bird2 = bird;

或者是:

Animal animal1 = new Bird("小鸟"); 

这里的 animal1 是一个父类的引用,指向一个子类的实例。这种写法被称为向上转型。

语法:父类名称 父类引用 = new 子类();

 

1.2.1 向上转型发生的时机
  • 直接赋值
  • 方法传参
  • 方法返回

1. 直接赋值

Animal animal = new Bird();

2. 方法传参


class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat(String food) {
        System.out.println(this.name + "正在吃" + food);
    }
}

class Bird extends Animal {
    public Bird(String name) {
        super(name);
    }

    public void fly() {
        System.out.println(this.name + "正在飞 ");
    }
}

class Cat extends Animal{
    public Cat(String name) {
        super(name);
    }
}
public class Demo2 {
    public static void main(String[] args) {
        // 创建一个动物类的对象
        Animal animal = new Animal("小动物");
        // 创建一个鸟类的对象
        Bird bird = new Bird("小鸟");
        Cat cat = new Cat("小猫");
        fun(animal,"食物");
        fun(cat,"猫粮");
        fun(bird,"虫子");

    }

    public static void fun(Animal animal, String food) {
        animal.eat(food);
    }
}

 

 Animal 有多个子类,fun 就得重载多少次。

3. 方法返回

此时 findAnimal 返回的是一个 Animal 类型的引用,但是实际上对应的是 Bird 实例。也就是把一个子类对象转换为一个 Animal 父类的引用。

1.3 重写

子类实现父类的同名方法,并且参数的类型和个数完全相同,这种情况称为覆写/重写/覆盖。

重写的规则:

  • 重写的方法方法名、参数列表必须一致,方法返回值也要一致(除了向上转型);
  • 重写方法时子类的方法的访问权限不能低于父类的方法访问权限;
  • 普通方法可以重写,但是 static 修饰的静态方法不能重写;
  • final 修饰的方法不能被重写。

当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。要想在子类调用父类中被重写的方法,则必须使用关键字 super。

重写和重载的区别可以看这篇。

2. 理解多态(多态示例)

使用多态设计程序。


class Shape {
    public void draw() {
    }
}

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

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

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

public class Demo1 {
    public static void main(String[] args) {
        Shape s1 = new Cycle();
        Shape s2 = new Rect();
        Shape s3 = new Flower();
        drawShape(s1);
        drawShape(s2);
        drawShape(s3);
    }

    private static void drawShape(Shape shape) {
        shape.draw();
    }
}

在上面这个例子中,三个对象都调用了 drawShape 方法,方法参数都是 Shape 类型,我们根据 shape 参数执行 draw 方法时发现,当传入不同对象时,draw 方法表现了不同的行为。当一个引用在不同场景下调用相同方法表现出来的不同行为。这就是多态。

3. 使用多态的好处 3.1 类调用者对类的使用成本进一步降低

多态能让类的调用者连这个类的类型时什么都不必知道,只需要知道这个对象具有某个方法即可。就好像 Animal 中有成百上千个子类,我们不需要这个类具体是啥,只要是它的子类,我们都可以使用 Aniaml 这个父类来操作子类。

3.2 简化性

能够降低代码的 "圈复杂度", 避免使用大量的 if - else。

比如让我们现在打印多个形状,如果灭有多态那代码就是:

但是如果使用多态,就不用使用多个 if - else 分支语句,使代码更加简单。

 

3.3 可扩展能力更强

如果没有多态,新增一个子类,调用者就得先了解此类,然后在调用出再新增一个分支,很不方便。

 

但是如果有多态,当有一个新的子类产生时,由于多态性,调用者不需要改变代码,使用父类就可以方便的扩展新的子类。

4. 多态的实现方法
  • 重写
  • 接口
  • 抽象类和抽象方法
5. 向下转型

向上转型是子类对象转成父类对象,向下转型就是父类对象转成子类对象。

代码示例:


class Animal2 {
    protected String name;

    public Animal2(String name) {
        this.name = name;
    }

    public void eat(String food) {
        System.out.println("我是一只小动物");
        System.out.println(this.name + "正在吃" + food);
    }
}

class Bird2 extends Animal2 {
    public Bird2(String name) {
        super(name);
    }

    public void eat(String food) {
        System.out.println("小李是一只小鸟");
        System.out.println(this.name + "正在吃" + food);
    }

    public void fly() {
        System.out.println(this.name + "正在飞");
    }
}

public class Demo3 {
    public static void main(String[] args) {
        Animal2 animal2 = new Bird2("小李");
        animal2.eat("小米");
        Bird2 bird2 = (Bird2)animal2;
        bird2.fly();
    }
}

在这个例子中,如果使用 animal2.fly() 调用 fly 的方法就会编译出错,因为 animal 的类型是 Animal, 此时编译器只知道这个类中有一个 eat 方法, 没有 fly 方法。所以如果想用 animal2 调用 fly 方法,就要使用向下转型。

Bird2 bird2 = (Bird2)animal2;
bird2.fly();

但是这样的向下转型有时会出现问题,比如:

Animal2 animal = new Cat2("小猫");
Bird2 bird = (Bird2)animal;
bird.fly();
// 执行结果, 抛出异常
Exception in thread "main" java.lang.ClassCastException: Cat cannot be cast to Bird
at Test.main(Test.java:35)
animal 本质上引用的是一个 Cat 对象, 是不能转成 Bird 对象的。运行时就会抛出异常。

所以,为了让向下转型更加安全,可以先判断 animal 的本质上是否是一个 Bird 实例,再转换。可以使用 instanceof 判断,如果是,返回 true,这时再进行向下转型。

        Animal2 animal = new Cat2("小猫");
        if (animal instanceof Bird2) {
            Bird2 bird = (Bird2)animal;
            bird.fly();
        } else{
            System.out.println("不能向下转型");
        }

 

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1007879.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号