Java基础 第二节 第十五课

举报
我是小白呀iamarookie 发表于 2021/09/10 22:31:00 2021/09/10
【摘要】 多态 概述引入定义前提 多态的体现代码展示 多态的好处引用类型转换向上转型向下转型为什么要转型定义类定义测试类 转型的异常 概述 引入 多态是继封装, 继承之后, 面向...

概述

引入

多态是继封装, 继承之后, 面向对象的第三大特征.

生活中, 比如跑的动作, 小猫, 小狗和大象, 跑起来是不一样的. 在比如飞的动作, 昆虫, 鸟类和飞机, 飞起来也是不一样的. 可见, 同一行为, 通过不同的事物, 可以体现出来的不同的形态. 多态, 描述的就是这样的状态.

定义

多态: 是指同一行为, 具有多个不同的表现形式.

前提

  1. 继承或者实现 (二选一)
  2. 方法的重写 (意义体现: 不重写, 无意义)
  3. 父类引用指向子类对象 (格式体现)

多态的体现

多态体现的格式:

父类类型 变量名 = new 子类对象;
变量名.方法名();

  
 
  • 1
  • 2

注: 父类类型: 指子类对象继承的父类类型, 或者实现的父类接口类型.

代码如下

Fu f = new Zi();
f.method();

  
 
  • 1
  • 2

当使用多态方式调用方法时, 首先检查父类中是否有该方法. 如果没有, 则编译错误; 如果有则执行的是子类重写后的方法.

代码展示

public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("吃鱼");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("吃狗粮");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

定义测试类:

public class Test2 {
    public static void main(String[] args) {
        // 多态形式, 创建对象
        Animal animal1 = new Cat();
        // 调用的是Cat的eat
        animal1.eat();  // 调试输出: 吃鱼

        // 多态形式, 创建对象
        Animal animal2 = new Dog();
        // 调用的是Dog的eat
        animal2.eat();  // 调试输出: 吃狗粮
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

多态的好处

实际开发的过程, 父亲类型作为方法形式参数, 传递子类对象给方法, 进行方法符调用. 这样更能体现出多态的扩展性与便利.

代码如下:

public class Test3 {
    public static void main(String[] args) {
        // 多态形式,创建对象
        Cat c = new Cat();
        Dog d = new Dog();
        // 调用showCatEat
        showCatEat(c);
        // 调用showDogEat
        showDogEat(d);
       /*
       以上两个方法, 均可以被showAnimalEat(Animal a)方法所替代
       而执行效果一致
       */
        showAnimalEat(c);
        showAnimalEat(d);
    }
    public static void showCatEat (Cat c){
        c.eat();
    }
    public static void showDogEat (Dog d){
        d.eat();
    }
    public static void showAnimalEat (Animal a) {
        a.eat();
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 由于多态的特性的支持, showAnimalEat 方法的 Animal 类型, 是 Cat 和 Dog 的父类类型. 父类类型接收子类对象, 当然可以把 Cat 对象和 Dog 对象, 传递给方法
  • 当 eat 方法执行时, 多态规定, 执行的是子类重写的方法. 那么效果自然与 showCatEat, showDogEat 方法一致. 所以, showAnimalEat 完全可以替代以上两种方法
  • 不仅仅是替代, 在扩展性方面, 无论之后再多的子类出现, 我们都不需要编写 showXxxEat 方法了. 直接使用 showAnimalEat 都可以完成

所以, 多态的好处体现在: 可以使程序编写的更简单, 并有良好的扩展性.

引用类型转换

多态的转型分为向上转型与向下转型两种.

向上转型

向上转型: 多态本身是子类类型向父类类型向上转换的过程, 这个过程是默认的. 即, 当父类引用指向一个子类对象是, 便是向上转型.

使用格式:

父类类型 变量名 = new 子类类型();
如:Animal a = new Cat();

  
 
  • 1
  • 2

向下转型

向下转型: 父亲类型向子类类型向下转换的过程, 这个过程是强制的. 即, 一个已经向上转型的子类地下, 将父类引用转为子类引用. 可以使用强制类型转换格式, 便是向下转型.

使用格式:

子类类型 变量名 = (子类类型) 父类变量名;
如:Cat c =(Cat) a;

  
 
  • 1
  • 2

为什么要转型

当使用多态方式调用方法时, 首先检测父类中是否有该方法. 如果没有, 则编译错误. 也就是说, 不能调用子类拥有而父类没有的方法. 编译都错误, 更别谈运行了. 这也是多态给我们带来的一点 “小麻烦”. 所以, 想要调用子类特有的方法, 必须做向下转型.

转型演示, 代码如下:

定义类

public abstract class Animal {
    abstract void eat();
}
class Cat extends Animal{

    @Override
    void eat() {
        System.out.println("吃鱼");
    }
    public void catchMouse() {
        System.out.println("抓老鼠");
    }
}
class Dog extends Animal {
    public void eat() {
        System.out.println("吃狗粮");
    }
    public void watchHouse() {
        System.out.println("看家");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

定义测试类

public class Test {
    public static void main(String[] args) {
        // 向上转型
        Animal animal = new Cat();
        animal.eat();  // 调用的是Cat的eat
        
        // 向下转型
        Cat cat = (Cat)animal;
        cat.catchMouse();  // 调用的是Cat的catchMouse
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

执行结果:
在这里插入图片描述

转型的异常

转型的过程中, 一不小心就会遇到这样的问题, 请看如下代码:

public class Test {
    public static void main(String[] args) {
        // 向上转型
        Animal animal = new Cat();
        animal.eat();  // 调用的是Cat的eat

        // 向下转型
        Dog dog = (Dog)animal;
        dog.watchHouse(); // 调用的是Dog的watchHouse (报错)
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

执行结果:
在这里插入图片描述
这段代码可以通过编译, 但是运行时, 却报出了ClassCaseException, 类型转换异常. 这是因为, 明明创建了 Cat 类型对象, 运行时, 当然不能转换成 Dog 对象的. 这两个类型并没有任何继承关系, 不符合类型转换的定义.

为了避免```ClassCastException``的发生, Java 提供了 instanceof 关键字, 给引用变量做类型的校验, 格式如下:

变量名 instanceof 数据类型
如果变量属于该数据类型, 返回true
如果变量不属于该数据类型, 返回false

  
 
  • 1
  • 2
  • 3

所以, 转换前, 嗯最好先做一个判断. 代码如下:

public class Test3 {
    public static void main(String[] args) {
        // 向上转型
        Animal animal = new Cat();
        animal.eat();  // 调用的是Cat的eat
        
        // 向下转型
        if (animal instanceof Cat){
            Cat cat = (Cat)animal;
            cat.catchMouse();        // 调用的是 Cat的catchMouse
        } else if (animal  instanceof Dog){
            Dog d = (Dog)animal;
            d.watchHouse();       // 调用的是 Dog的watchHouse
        }
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

文章来源: iamarookie.blog.csdn.net,作者:我是小白呀,版权归原作者所有,如需转载,请联系作者。

原文链接:iamarookie.blog.csdn.net/article/details/110156536

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。