Java面向对象三大基本特征之多态

news/2024/5/5 2:17:17/文章来源:https://blog.csdn.net/lv121218/article/details/128006136

多态性是面向对象编程的又一个重要特征,那么多态是什么呢?

一、多态的概念

1.概念:多态是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义。

2.多态现实意义的理解:多态是同一个行为具有多个不同表现形式或形态的能力;多态就是同一个接口,使用不同的实例而执行不同操作。

(1)现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个具体的同学张三既是学生也是人,即出现两种形态。                                                                                                            

(2)Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。

二、多态的使用

1.多态的使用前提:

java实现多态有 3 个必要条件:继承、重写和向上转型

(1)继承:在多态中必须存在有继承关系的子类和父类。

(2)方法重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。

(3)向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。即父类引用变量可以指向子类对象

父类类型 变量名=new 子类类型();

2.示例:接下来我们用代码来帮助理解

父类:Animal类

public class Animal {public String name;public int health;//健康值public int love;//亲密度public Animal() {//无参构造super();}public Animal(String name, int health, int love) {//有参构造super();this.name = name;this.health = health;this.love = love;}//定义一个方法public void test(){System.out.println("我是Animal类中的test()方法");}}

子类:Cat类

public class Cat extends Animal {public String color;//颜色public Cat() {super();}public Cat(String name, int health, int love, String color) {super(name, health, love);this.color = color;}// 重写Animal类中的test()方法public void test() {System.out.println("我是Cat类中的test()方法");}public void play(){System.out.println("我是Cat类中的play()方法");}}

子类:Dog类

public class Dog extends Animal {public String strain;//种类public Dog() {super();//调用父类Animal类中的无参构造方法}public Dog(String name, int health, int love, String strain) {super(name, health, love);//调用父类Animal类中的有参构造方法this.strain = strain;}//重写Animal类中的test()方法public void test(){System.out.println("我是Dog类中的test()方法");}public void eat(){System.out.println("我是Dog类中的eat()方法");}
}

测试:Test类

public class Test {public static void main(String[] args) {//创建Dog类对象Dog dog = new Dog("旺财", 100, 100, "金毛");dog.test();//创建Cat类对象Cat cat = new Cat("Tom", 100, 99, "蓝色");cat.test();System.out.println("--------------------------");//多态:同一个父类引用,指向不同的子类实例,执行不同的操作。方法重写是实现多态的前提//向上转型(自动类型转换):父类的引用指向子类的实例(对象)Animal animal = new Dog("来福", 100, 98, "泰迪");animal.test();//eat()方法是Dog类中独有的方法、父类引用无法直接调用子类中特有的方法,如果父类引用需要使用子类中独有的的方法,需要将父类引用强制类型转换为子类
//		animal.eat();//向下转型(强制类型转换):子类的引用指向父类的引用Dog dog2=(Dog)animal;dog2.eat();animal = new Cat("加菲猫", 85, 88, "黄色");animal.test();//play()方法是Cat类中独有的方法,父类引用无法直接调用子类中特有的方法,如果父类引用需要使用子类中独有的的方法,需要将父类引用强制类型转换为子类
//		animal.play();//在向下转型过程中,容易出现类型转换异常ClassCastException,将父类引用转换成了其它的子类对象,所以在转换之前需要对父类引用类型进行判断
//		Dog cat2 =(Dog)animal;if(animal instanceof Dog){Dog dog3 =(Dog)animal;dog3.eat();}else if(animal instanceof Cat){Cat cat3 =(Cat)animal;cat3.play();}}}

结果:

由上述代码我们可以看到,创建了一个Animal引用指向Dog类实例,然后使用animal引用调用test()方法,实际上调用的却是Dog类中的test()方法,这就是多态的一种应用;

三、Java中实现和使用多态的主要方式:

1.使用父类作为方法的形参:

示例:

父类:Animal类

public class Animal {private String name;private int health;//健康值private int love;public Animal() {super();}public Animal(String name, int health, int love) {super();this.name = name;this.health = health;this.love = love;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getHealth() {return health;}public void setHealth(int health) {this.health = health;}public int getLove() {return love;}public void setLove(int love) {this.love = love;}//定义一个方法实现Animal看病public void lookDoctor(){System.out.println("我是Animal类中看病的lookDoctor()方法");}
}

子类:Cat类

public class Cat extends Animal {private String color;public Cat() {super();}public Cat(String name, int health, int love, String color) {super(name, health, love);this.color = color;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}//重写Animal类中的lookDoctor()方法@Overridepublic void lookDoctor() {System.out.println("猫生病了,打针和吃药.....");this.setHealth(85);}}

子类:Dog类

public class Dog extends Animal {private String strain;public Dog() {super();//调用父类Animal类中的无参构造方法}public Dog(String name, int health, int love, String strain) {super(name, health, love);//调用父类Animal类中的有参构造方法this.strain = strain;}public String getStrain() {return strain;}public void setStrain(String strain) {this.strain = strain;}//重写Animal类中的lookDoctor()方法@Overridepublic void lookDoctor() {//健康值小于60的时候System.out.println("狗生病了,打针.......");this.setHealth(70);}
}

子类:Penguin类

public class Penguin extends Animal {private char sex;public Penguin() {super();}public Penguin(String name, int health, int love, char sex) {super(name, health, love);this.sex = sex;}public char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}// 重写Animal类中的lookDoctor()方法@Overridepublic void lookDoctor() {// 健康值小于60的时候System.out.println("企鹅生病了,吃药.......");this.setHealth(75);}}

主人类:Master类

public class Master {//定义给Animal对象看病的方法public void cure(Animal animal){//animal对象健康值小于60的时候需要看病if(animal.getHealth()<60){animal.lookDoctor();}}}

测试类:Test类

public class Test {public static void main(String[] args) {Master master = new Master();//创建Dog类对象Dog dog1 = new Dog("旺财", 30, 99, "藏獒");System.out.println(dog1.getHealth());//调用方法原则一:方法需要什么类型的参数就需要给什么类型的参数---》方法需要什么类型的参数就需要给什么类型的参数(包括其子类)master.cure(dog1);System.out.println(dog1.getHealth());System.out.println("----------------");//创建Penguin类对象Penguin penguin1 = new Penguin("QQ", 45, 90, '母');System.out.println(penguin1.getHealth());master.cure(penguin1);System.out.println(penguin1.getHealth());System.out.println("----------------");Animal animal = new Dog("来福", 20, 100, "拉布拉多");System.out.println(animal.getHealth());master.cure(animal);System.out.println(animal.getHealth());System.out.println("---------------------------------");animal = new Penguin("QQ", 50, 92, '公');System.out.println(animal.getHealth());master.cure(animal);System.out.println(animal.getHealth());}}

结果:

 可以看到在Master类中将Animal类对象作为一个形参,来进行方法的调用;

2.使用父类作为方法的返回值:

父类:Animal类

public abstract class Animal {//定义一个动物叫的方法public abstract void shout();}

子类:Cat类

public class Cat extends Animal {@Overridepublic void shout() {System.out.println("喵喵喵");}}

子类:Dog类

public class Dog extends Animal {@Overridepublic void shout() {System.out.println("汪汪汪");}}

主人类:Master类

public class Master {//将父类Animal作为方法的形参使用,是多态的使用方式之一//定义一个方法:实现让动物叫public void letShout(Animal animal){animal.shout();}//将父类Animal作为方法的返回值,也是多态的使用方式之一public Animal giveAnimal(String type){Animal animal = null;if(type.equals("狗")){animal = new Dog();}else{animal = new Cat();}return animal;}}

测试类:Test类

public class Test {public static void main(String[] args) {Master master = new Master();// Animal是抽象类。不能直接实例化,可以使用多态的形式,将animal引用指向子类实例// Animal animal = new Animal();Animal animal = new Dog();master.letShout(animal);animal = new Cat();master.letShout(animal);System.out.println("-----------------------");//赠送动物Scanner sc = new Scanner(System.in);System.out.println("你想要什么动物?(猫/狗)");String pet =sc.next();Animal ani=master.giveAnimal(pet);ani.shout();}}

可以看到Master类中父类Animal类作为方法的返回值。

四、多态的必要性

使用多态的好处:

1.提高了代码的可维护性

2.可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。

五、多态的局限性

1.当父类引用指向子类对象时,父类引用是不能直接调用子类特有的方法的。需要向下转型(强制类型转换)。

向下转型(强制类型转换)格式:

父类类型 父类对象引用=new 子类类型();//向上转型(自动类型转换):父类的引用指向子类的实例(对象

子类类型  子类对象引用=(子类类型)父类对象引用;//向下转型(强制类型转换):子类的引用指向父类的引用

向下转换后才能调用子类特有的方法。

2.同时,在向下转型的过程中,容易出现类型转换异常ClassCastException,将父类引用转换成了其它的子类对象,所以在转换之前需要对父类引用类型进行判断

这时就需要用到instanceof关键字进行判断

 if(animal instanceof Dog){
            Dog dog =(Dog)animal;
            dog.eat();//Dog类中独有方法
        }else if(animal instanceof Cat){
            Cat cat =(Cat)animal;
            cat.play();//Cat类中独有方法
        }

注意:使用instanceof时,对象的类型必须和instanceof后面的参数所指定的类在继承上有上下级关系


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_224796.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数商云采购协同系统邀请招标实施步骤 | 助力建筑工程企业采购工作降本增效

建筑工程行业作为拉动我国工业发展与国民经济发展的重要支柱产业之一&#xff0c;目前已进入稳定发展阶段。在新基建热潮下&#xff0c;建筑工程行业加速向自动化、智能化方向发展&#xff0c;如何借助数字化技术提升管理水平&#xff0c;实现新价值增长&#xff0c;成为行业企…

220kV降压变电所电气部分初步设计33号

目录 1 绪论 5 &#xff11;.&#xff11; 概述 5 &#xff11;.&#xff12; 本次设计内容 5 &#xff11;.&#xff13; 本次设计任务 5 2 变电站总体分析 6 2.&#xff11;变电所总体分析 6 2.2主变压器选择 7 3 电气主接线选择 10 3.1 电气主接线的概念 10 3.2 电气主接…

【零基础入门SpringMVC】第一期——开篇导论

一、导论 $ 什么是MVC&#xff1f; MVC 是一种将软件按照 模型、视图、控制器来划分的一种架构思维MVC全称SpringWebMVC&#xff0c;那么M、V、C分别代表什么呢&#xff1f; M&#xff1a;Model 代表模型层&#xff0c;作用就是处理数据&#xff0c;在我们SpringMVC中&#x…

python自学入门(打卡十)2022-11-22

Pytest与Unittest区别 参考资料&#xff1a;https://blog.csdn.net/qq_33385691/article/details/112004487 pytest用例规则 文件名以test_.py文件和test.py 以test_开头的函数 以Test开头的类&#xff0c;test_开头的方法&#xff0c;并且不能带有__init_ 方法 所有的包pake…

​LabVIEW从另一个VI或通过VI服务器访问正在运行的可执行文件

​LabVIEW从另一个VI或通过VI服务器访问正在运行的可执行文件 有没有办法从另一个VI或可执行文件访问正在运行的LabVIEW可执行文件。例如&#xff0c;从显示控件获取值&#xff0c;为控件设置值&#xff0c;以及初始化运行LabVIEW可执行文件VI的前面板。 在正在运行的可执行文…

11.23二叉树

目录 一.笔试强训习题订正 1.选择题 2.编程题-组队竞赛 3.删除公共字符 解法1 哈希映射思想 解法2 暴力解法 解法3 substring解法replaceAll() 二.二叉树相关Oj题 1.二叉树的遍历 2.二叉树分层遍历 三.二叉树的最近公共祖先 1.思路一 2.思路2 四.将二叉搜索树转化…

web网页大作业——基于HTML+CSS+JavaScript制作摄影之家网站

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

java项目测试成功后部署到服务器上的相关问题

1.java项目是如何部署给用户使用的? 前提&#xff1a; 以一个web项目为例&#xff0c; 使用工具&#xff1a;开发工具&#xff1a;IDEA&#xff1b;Tomcat&#xff08;应用服务器&#xff09;&#xff1b;Navicat&#xff08;数据库&#xff09;&#xff1b;Jenkins&#xff…

鲲鹏devkit编译调试工具——《sudoku》作业解析

《sudoku》作业解析 本次实验以sudoku项目为例介绍鲲鹏编译调试插件的基本使用方法 本次实验的步骤主要为 获取源码安装鲲鹏编译调试插件服务器配置进行代码同步配置配置测试任务进行编译调试 接下来我们先获取本次实验所需要的源码 获取源码 sudoku项目已经上传到github使…

CVPR‘15 Joint action recognition and pose estimation from video

任务&#xff1a;action recognition and pose estimation 思路&#xff1a;对动作和姿态进行统一建模&#xff0c;将动作分成姿态&#xff0c;再将姿态分成part&#xff0c;学习三种level特征&#xff0c;通过动态规划有效的推断动作标签和姿态。 方法&#xff1a;统一建模…

鼠标经过图片在边框内放大动效

鼠标没有经过&#xff1a; 鼠标经过的时候&#xff0c;看图&#xff0c;应该可以看出变化吧&#xff01;图有放大的效果。 样式&#xff1a;图片由一个盒子包着&#xff0c;盒子加上overflow:hidden的样式&#xff0c;即可以保证图片在边框内放大。 然后给图片加上动画效果就可…

Vue常用知识点汇总

1. Vue常见的指令有哪些&#xff0c;有什么用 &#xff08;1&#xff09;v-text&#xff1a; 会替换掉元素里的内容&#xff1b; &#xff08;2&#xff09;v-html&#xff1a; 可以渲染html界面&#xff1b; &#xff08;3&#xff09;v-clock&#xff1a; 防止界面闪烁&…

JavaScript开发工具WebStorm入门教程:开始运行WebStorm(一)

WebStorm是一个JavaScript开发工具&#xff0c;用于JavaScript及其相关技术编码&#xff0c;包括TypeScript、React、Vue、Angular、Node.js、HTML和样式表。就像IntelliJ IDEA和其他JetBrains ide一样&#xff0c;WebStorm让您的开发体验更愉快&#xff0c;自动化日常工作&…

7种主流数据分析软件比较及经典教材推荐

前言 STATA 软件优点&#xff1a;Stata以其简单易懂和功能强大受到初学者和高级用户的普遍欢迎。使用时可以每次只输入一个命令&#xff0c;也可以通过一个Stata程序一次输入多个命令。这样的话即使发生错误&#xff0c;也较容易找出并加以修改。尽管Stata的数据管理能力没有…

用DIV+CSS技术设计我的家乡网站(web前端网页制作课作业)南宁绿城之都

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

Xshell连接不上创建的虚拟机

1.输入ip a查看是否有对应的网卡ip 更改前&#xff1a; 更改后&#xff1a; 具体看下面博客的步骤&#xff0c;这里不详细赘述 (137条消息) Linux虚拟机联网步骤&#xff08;修改网络配置信息&#xff09;_袁梦码的博客-CSDN博客_怎么让linux虚拟机联网 2.关闭防火墙 永久关…

C语言实现冒泡排序(图解)

目录 一、冒泡排序是什么&#xff1f; 二、图解冒泡排序过程 三、代码实现 3.1易错点&#xff08;切记切记&#xff09; 四、优化 4.1优化代码 一、冒泡排序是什么&#xff1f; int arr[]{9,8,7,6,5,4,3,2,1,0} &#xff0c;像这样的数组&#xff0c;升序排序。 冒泡排序…

linux 清理垃圾文件

linux的文件系统比windows的要优秀&#xff0c;不会产生碎片&#xff0c;对于长时间运行的服务器来说尤为重要&#xff0c;而且linux系统本身也不会像windows一样产生大量的垃圾文件。不知道这个说法有没有可信度!至少我们可以确定的是linux系统的文件系统是比较优秀的! linux…

使用html+css+js实现一个静态页面(含源码)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

MASA Framework 事件总线 - 进程内事件总线

概述 事件总线是一种事件发布/订阅结构&#xff0c;通过发布订阅模式可以解耦不同架构层级&#xff0c;同样它也可以来解决业务之间的耦合&#xff0c;它有以下优点 松耦合横切关注点可测试性事件驱动 发布订阅模式 通过下图我们可以快速了解发布订阅模式的本质 订阅者将自…