博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JAVA笔记(十一)面向对象--多态
阅读量:2094 次
发布时间:2019-04-29

本文共 9267 字,大约阅读时间需要 30 分钟。

引言:面向对象三大特征:封装,继承,多态,前面我们已经学习了封装和继承,本章节我们来详细讲解多态,该章节知识点需要使用继承知识点,如果你还未学习继承,请出门右转,学习完再回来。

一、为什么使用多态:

讲解多态之前,我们先来看一个问题,实际需求中有两种动物,狗和企鹅,现在我们需要编写一个程序实现动物饿了,动物主人喂食的过程:

在这里插入图片描述

经过分析,我们发现两种动物有相同的属性(昵称:name,健康值:health,亲密度:love)和相同的方法(属性对应的set/get方法及相关打印方法),那么对系统进行优化我们可以将两者相同属性和方法进一步 抽取形成共同的父类动物类,但是我们发现不同动物吃的东西不同,不同宠物吃完以后恢复的体力值不同,如果我们把动物吃东西的过程看做一个方法,那么两个类的吃东西的方法是不同的。

通过分析,我们可以得到以下类:

  • 动物类:属性(共同属性),方法(共同方法)

  • 狗类:属性(xx),方法(狗吃食的方法)

  • 企鹅类:属性(xx),方法(企鹅吃食的方法)

  • 动物主人类:属性(xx),方法(给狗狗喂食的方法,给企鹅喂食的方法)

  • 编写测试类:动物主人给狗喂食的方法,动物主人给企鹅喂食的方法

代码如下:

父类:

package cn.hz;/*** 宠物类,狗狗和企鹅的父类。 * * @author  hz*/public  class Pet {
private String name = "无名氏";// 昵称 private int health = 100;// 健康值 private int love = 0;// 亲密度 /** * 有参构造方法。 * @param name 昵称 */ public Pet(){
} public Pet(String name) {
this.name = name; } public void setName(String name) {
this.name = name; } public void setHealth(int health) {
this.health = health; } public void setLove(int love) {
this.love = love; } public String getName() {
return name; } public int getHealth() {
return health; } public int getLove() {
return love; } /** * 输出宠物信息。 */ public void print() {
System.out.println("宠物的自白:\n我的名字叫" + this.name + ",健康值是" + this.health + ",和主人的亲密度是" + this.love + "。"); } }

子类:

package cn.hz;/** * 狗狗类,宠物的子类。 * * @author hz */public class Dog extends Pet {
private String strain;// 品种 /** * 有参构造方法。 * @param name 昵称 * @param strain 品种 */ public Dog(String name, String strain) {
super(name); this.strain = strain; } public String getStrain() {
return strain; } /** * 重写父类的print方法。 */ public void print(){
super.print(); //调用父类的print方法 System.out.println("我是一只 " + this.strain + "。"); } /** * 实现吃食方法。 */ public void eat() {
if(getHealth()>=100){
System.out.println("狗狗"+this.getName() +"吃饱了,不需要喂食了!"); }else{
this.setHealth(this.getHealth()+3); System.out.println("狗狗"+this.getName() + "吃饱啦!健康值增加3。"); } }}
package cn.hz;/** * 企鹅类,宠物的子类。 * * @author  hz */public class Penguin extends Pet {
private String sex;// 性别 /** * 有参构造方法。 * @param name 昵称 * @param sex 性别 */ public Penguin(String name, String sex) {
super(name); this.sex = sex; } public String getSex() {
return sex; } /** * 重写父类的print方法。 */ public void print() {
super.print(); System.out.println("性别是 " + this.sex + "。"); } /** * 实现吃食方法。 */ public void eat() {
if(getHealth()>=100){
System.out.println("企鹅"+this.getName() +"吃饱了,不需要喂食了!"); }else{
this.setHealth(this.getHealth()+5); System.out.println("企鹅"+this.getName() + "吃饱啦!健康值增加3。"); } }}

动物主人类:

package cn.hz;/** * 主人类 * @author  hz */public class Master {
private String name = "";// 主人名字 private int money = 0; // 元宝数 /** * 有参构造方法。 * @param name 主人名字 * @param money 元宝数 */ public Master(String name, int money) {
this.name = name; this.money = money; } public void setName(String name) {
this.name = name; } public void setMoney(int money) {
this.money = money; } public int getMoney() {
return money; } public String getName() {
return name; } /** * 主人给Dog喂食。 */ public void feed(Dog dog) {
dog.eat(); } /** * 主人给Penguin喂食。 */ public void feed(Penguin pgn) {
pgn.eat(); }}

测试类:

package cn.hz;/** * 测试类,领养宠物并喂食。 * @author  hz */public class Test {
public static void main(String[] args) {
Dog dog = new Dog("欧欧", "雪娜瑞"); dog.setHealth(80); //设置健康值,以便正常喂食 Penguin pgn = new Penguin("楠楠", "Q妹"); Master master=new Master("王先生",100); master.feed(dog);//主人给狗狗喂食 master.feed(pgn);//主人给企鹅喂食 pgn.setHealth(80); //设置健康值,以便正常喂食 master.feed(pgn);//主人再次给企鹅喂食 }}

演示效果如下:

在这里插入图片描述

通过上述代码我们实现了动物喂食功能,,如果再领养XXX宠物,并需要给XXX喂食,怎么办?

  • 添加XXX类,继承Pet类,实现吃食方法
  • 修改Master类,添加给XXX喂食的方法

这个时候我们就会发现问题了,对于上述代码,只要是有新的功能添加,我们就需要频繁修改代码,代码可扩展性、可维护性差,如何优化? java中提供了一种解决方法-多态。

二、多态:

1.定义:

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

多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xZOpIGu1-1623135296110)( 多态体现图1.png)]

如我们上述的例子,动物主人需要给不同的动物喂食,都是实现喂食功能,但是喂食的对象实例不同,那么我们就可以使用多条进行实现。

2.多态存在的必然条件:

  • 继承:编写具有继承关系的父类和子类
  • 重写:子类重写父类方法
  • 父类引用指向子类对象:Parent p = new Child(); -自动向上转型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7mcTahWv-1623135296115)( 多态存在的必然条件.png)]

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

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

3.多态实现方式:

实现多态有两种方式:

  • 使用父类作为方法形参实现多态
  • 使用父类作为方法返回值实现多态

首先我们来看父类作为方法形参实现多态,以上述动物案例实现为例,添加新动物就需要对代码进行修改,例如我们添加一个新的宠物-猫的类,如果使用多态进行优化呢?

首先我们分析两种动物都需要有吃的方法,但是吃的东西和实现的结果不同,如果我们把吃东西看做方法,也就是方法体是不同的,如果我们把吃东西的方法在父类中定义成抽象方法,不同的子类去做不同的实现,那么我们在喂食的时候直接喂食父类,至于具体是子类我们不需要关系,等子类实例化以后,父类引用指向子类引用即可,这样我们的代码的扩展性就得到了极大的提升。

代码如下:

父类:定义为抽象类,编写抽象方法-吃东西的方法

package cn.hz;/*** 宠物类,狗狗和企鹅的父类。 * @author  hz*/public abstract class Pet {
private String name = "无名氏";// 昵称 private int health = 100;// 健康值 private int love = 0;// 亲密度 /** * 抽象方法eat(),负责宠物吃饭功能。 */ public abstract void eat(); /** * 有参构造方法。 * @param name 昵称 */ public Pet(){
} public Pet(String name) {
this.name = name; } public void setName(String name) {
this.name = name; } public void setHealth(int health) {
this.health = health; } public void setLove(int love) {
this.love = love; } public String getName() {
return name; } public int getHealth() {
return health; } public int getLove() {
return love; } /** * 输出宠物信息。 */ public void print() {
System.out.println("宠物的自白:\n我的名字叫" + this.name + ",健康值是" + this.health + ",和主人的亲密度是" + this.love + "。"); } }

子类: 子类重写父类的抽象方法

package cn.hz;/** * 企鹅类,宠物的子类。 * @author  hz */public class Penguin extends Pet {
private String sex;// 性别 /** * 有参构造方法。 * @param name 昵称 * @param sex 性别 */ public Penguin(String name, String sex) {
super(name); this.sex = sex; } public String getSex() {
return sex; } /** * 重写父类的print方法。 */ public void print() {
super.print(); System.out.println("性别是 " + this.sex + "。"); } /** * 实现吃食方法。 */ public void eat() {
if(getHealth()>=100){
System.out.println("企鹅"+this.getName() +"吃饱了,不需要喂食了!"); }else{
this.setHealth(this.getHealth()+5); System.out.println("企鹅"+this.getName() + "吃饱啦!健康值增加3。"); } }}
package cn.hz;/** * 企鹅类,宠物的子类。 * @author  hz */public class Penguin extends Pet {
private String sex;// 性别 /** * 有参构造方法。 * @param name 昵称 * @param sex 性别 */ public Penguin(String name, String sex) {
super(name); this.sex = sex; } public String getSex() {
return sex; } /** * 重写父类的print方法。 */ public void print() {
super.print(); System.out.println("性别是 " + this.sex + "。"); } /** * 实现吃食方法。 */ public void eat() {
if(getHealth()>=100){
System.out.println("企鹅"+this.getName() +"吃饱了,不需要喂食了!"); }else{
this.setHealth(this.getHealth()+5); System.out.println("企鹅"+this.getName() + "吃饱啦!健康值增加3。"); } }}
package cn.hz;/** * 狗狗类,宠物的子类。 * @author  hz */public class Dog extends Pet {
private String strain;// 品种 /** * 有参构造方法。 * @param name 昵称 * @param strain 品种 */ public Dog(String name, String strain) {
super(name); this.strain = strain; } public String getStrain() {
return strain; } /** * 重写父类的print方法。 */ public void print(){
super.print(); //调用父类的print方法 System.out.println("我是一只 " + this.strain + "。"); } /** * 实现吃食方法。 */ public void eat() {
if(getHealth()>=100){
System.out.println("狗狗"+this.getName() +"吃饱了,不需要喂食了!"); }else{
this.setHealth(this.getHealth()+3); System.out.println("狗狗"+this.getName() + "吃饱啦!健康值增加3。"); } }}
package cn.hz;/** * 猫类,宠物的子类。 * @author  hz */public class Cat extends Pet {
private String color;//颜色 public Cat(String name, String color) {
super(name); this.color = color; } public void setColor(String color) {
this.color = color; } public String getColor() {
return color; } /** * 实现吃饭方法 */ public void eat() {
if(getHealth()>=100){
System.out.println("狗狗"+this.getName() +"吃饱了,不需要喂食了!"); }else{
this.setHealth(this.getHealth()+4); System.out.println("猫咪"+this.getName() + "吃饱啦!体力增加4。"); } }}

**宠物主人类:**喂食方法就一个,参数为父类

package cn.hz;/** * 主人类。 * @author  hz */public class Master {	private String name = "";// 主人名字	private int money = 0; // 元宝数	/**	 * 有参构造方法。	 * @param name 主人名字	 * @param money 元宝数	 */	public Master(String name, int money) {		this.name = name;		this.money = money;	}		public void setName(String name) {		this.name = name;	}	public void setMoney(int money) {		this.money = money;	}	public int getMoney() {		return money;	}	public String getName() {		return name;	}	/**	 * 主人给宠物喂食。	 */	public void feed(Pet pet) {		pet.eat();	}}

**测试类:**父类引用指向子类对象

package cn.hz;/** * 测试类,领养宠物并喂食。 * @author  hz */public class Test {
public static void main(String[] args) {
Dog dog = new Dog("欧欧", "雪娜瑞"); Penguin pgn = new Penguin("楠楠", "Q妹"); Cat cat=new Cat("Tomcat","黄色"); dog.setHealth(80); //设置健康值,以便正常喂食 pgn.setHealth(80); //设置健康值,以便正常喂食 cat.setHealth(80); //设置健康值,以便正常喂食 Master master=new Master("王先生",100); master.feed(dog);//主人给狗狗喂食 master.feed(pgn);//主人给企鹅喂食 master.feed(cat);//主人给猫喂食 }}

通过对比我们可以发现,使用父类作为方法参数,使用时将具体子类传入,通过使用父类引用指向子类对象,这样可以极大减少代码的修改,从而提高代码的扩展性。

接着我们再来看父类作为返回值实现多态,如果我们现在有新的需求,编写代码实现动物的领养功能,如果按照传统方法,则我们需要在master类中定义不同动物的领养方法,如果用多态呢?那么我们只需要定义领养动物的方法的返回值为动物类,然后通过方法的具体判定返回不同的子类即可,代码相似,省略。

通过上述案例我们知道,不管是父类作为方法参数还是父类作为返回值实现多态,都极大的提高了代码的可扩展性,但是注意在使用多态时类型转换问题。

4.多态的优点:

  • 消除类型之间的耦合关系
  • 可替换性
  • 可扩充性
  • 接口性
  • 灵活性
  • 简化性

转载地址:http://yuuhf.baihongyu.com/

你可能感兴趣的文章
Java项目导出可运行的jar文件
查看>>
Java文件夹操作,判断多级路径是否存在,不存在就创建(包括windows和linux下的路径字符分析),兼容Windows和Linux
查看>>
JAVA读取PROPERTIES配置文件
查看>>
Linux中执行shell脚本的4种方法总结
查看>>
BufferedInputStream(缓冲输入流)详解
查看>>
修改linux文件权限命令:chmod
查看>>
Linux vi/vim编辑器常用命令与用法总结
查看>>
如何使用Git Bash Here,将本地项目传到github上
查看>>
eclipse git控件操作 回退到历史提交 重置 删除(撤销)历史的某次提交
查看>>
Oracle | 给表和字段添加注释
查看>>
java比较日期大小及日期与字符串的转换【SimpleDateFormat操作实例】
查看>>
Oracle新表使用序列(sequence)作为插入值,初始值不是第一个,oraclesequence
查看>>
java中System.exit()方法
查看>>
在hbase shell中过滤器的简单使用
查看>>
java静态方法和实例方法
查看>>
java多线程并发去调用一个类的静态方法,会有问题吗?
查看>>
关于JAVA中的static方法、并发问题以及JAVA运行时内存模型
查看>>
Java命令学习系列(一)——Jps
查看>>
java如何计算程序运行时间
查看>>
Java Calendar 类的时间操作
查看>>