Java三大特性之多态详解

 更新时间:2022年10月11日 14:26:08   作者:共饮一杯无  
多态是继封装、继承之后,面向对象的第三大特性。多态: 是指同一行为,具有多个不同表现形式。本文将来和大家详细说说Java中的多态,需要的可以了解一下

概述

引入

多态是继封装、继承之后,面向对象的第三大特性。 生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。

定义

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

多态的体现

多态体现的格式:

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

父类类型:指子类对象继承的父类类型,或者实现的父接口类型。 代码如下:

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

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

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

定义子类:

class Cat extends Animal {
    public void eat() {
        System.out.println("吃鱼🐟");
    }
}
class Dog extends Animal {
    public void eat() {
        System.out.println("吃骨头🍖");
    }
}

定义测试类:

public class Test {
    public static void main(String[] args) {
        // 多态形式,创建对象
        Animal a1 = new Cat();
        // 调用的是 Cat 的 eat
        a1.eat();
        // 多态形式,创建对象
        Animal a2 = new Dog();
        // 调用的是 Dog 的 eat
        a2.eat();
    }
}

多态的好处

实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。代码如下: 定义父类:

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

定义子类:

class Cat extends Animal {
    public void eat() {
        System.out.println("吃鱼🐟");
    }
}
class Dog extends Animal {
    public void eat() {
        System.out.println("吃骨头🍖");
    }
}

定义测试类:

public class Test {
    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();
    }
}

由于多态特性的支持,showAnimalEat方法的Animal类型,是Cat和Dog的父类类型,父类类型接收子类对象,当然可以把Cat对象和Dog对象,传递给方法。 当eat方法执行时,多态规定,执行的是子类重写的方法,那么效果自然与showCatEat、showDogEat方法一致, 所以showAnimalEat完全可以替代以上两方法。 不仅仅是替代,在扩展性方面,无论之后再多的子类出现,我们都不需要编写showXxxEat方法了,直接使用 showAnimalEat都可以完成。 所以,多态的好处,体现在,可以使程序编写的更简单,并有良好的扩展。

引用类型转换

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

向上转型

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

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

向下转型

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

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

为什么要转型

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

abstract class Animal {
    abstract void eat();
}
class Cat extends Animal {
    public 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("看家👀");
    }
}

定义测试类:

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

转型的异常

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

public class Test {
    public static void main(String[] args) {
        // 向上转型
        Animal a = new Cat();
        a.eat(); // 调用的是 Cat 的 eat
        // 向下转型
        Dog d = (Dog)a;
        d.watchHouse(); // 调用的是 Dog 的 watchHouse 【运行报错】
    }
}

这段代码可以通过编译,但是运行时,却报出了 ClassCastException ,类型转换异常!这是因为,明明创建了Cat类型对象,运行时,当然不能转换成Dog对象的。这两个类型并没有任何继承关系,不符合类型转换的定义。为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:

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

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

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

以上就是Java三大特性之多态详解的详细内容,更多关于Java多态的资料请关注脚本之家其它相关文章!

相关文章

  • SpringBoot中@MessageMapping注解的原理及使用详解

    SpringBoot中@MessageMapping注解的原理及使用详解

    这篇文章主要介绍了SpringBoot中@MessageMapping注解的原理及使用详解,@MessageMapping注解是Spring Boot提供的一个重要的注解之一,它可以帮助我们处理WebSocket消息,需要的朋友可以参考下
    2023-07-07
  • Java 如何调用long的最大值和最小值

    Java 如何调用long的最大值和最小值

    这篇文章主要介绍了Java 如何调用long的最大值和最小值的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • 关于spring aop两种代理混用的问题

    关于spring aop两种代理混用的问题

    这篇文章主要介绍了关于spring aop两种代理混用的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • JAVA十大排序算法之基数排序详解

    JAVA十大排序算法之基数排序详解

    这篇文章主要介绍了java中的基数排序,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • Java中文乱码解决方案全解析,让你的程序“说人话”!

    Java中文乱码解决方案全解析,让你的程序“说人话”!

    探索Java中文乱码解决方案全解析,让你的程序终于能“说人话”!厌倦了看着一串串的问号或者奇怪符号吗?跟着我们的指南,一步步轻松解锁中文乱码的秘密,让你的代码清晰表达每一个字,需要的朋友可以参考下
    2024-02-02
  • SpringMVC框架中使用Filter实现请求日志打印方式

    SpringMVC框架中使用Filter实现请求日志打印方式

    这篇文章主要介绍了SpringMVC框架中使用Filter实现请求日志打印方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Spring Bean注册与注入实现方法详解

    Spring Bean注册与注入实现方法详解

    首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入。依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖。Spring容器中支持的依赖注入方式主要有属性注入、构造函数注入、工厂方法注入
    2022-10-10
  • 详解Java Spring各种依赖注入注解的区别

    详解Java Spring各种依赖注入注解的区别

    这篇文章主要介绍了详解Java Spring各种依赖注入注解的区别的相关资料,需要的朋友可以参考下
    2016-03-03
  • SpringMVC ajax请求的处理方法介绍

    SpringMVC ajax请求的处理方法介绍

    Ajax即异步的 JavaScript和XML,是一种无需重新加载整个网页的情况下,能够更新部分模块的网页技术,下面这篇文章主要给大家介绍了关于SpringMVC Ajax请求的处理,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • Spring结合WebSocket实现实时通信的教程详解

    Spring结合WebSocket实现实时通信的教程详解

    WebSocket 是基于TCP/IP协议,独立于HTTP协议的通信协议,本文将使用Spring结合WebSocket实现实时通信功能,有需要的小伙伴可以参考一下
    2024-01-01

最新评论