百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 文章教程 > 正文

JAVA笔记(十一)面向对象——多态

xsobi 2025-01-03 19:37 1 浏览

JAVA面向对象(六)--多态

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

一、为什么使用多态:

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



经过分析,我们发现两种动物有相同的属性(昵称: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.定义:

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

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



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

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

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



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

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

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.多态的优点:

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

相关推荐

听说你还不知道Java代码是怎么运行的?

作者:Jay_huaxiao前言作为一名Java程序员,我们需要知道Java代码是怎么运行的。最近复习了深入理解Java虚拟机这本书,做了一下笔记,希望对大家有帮助,如果有不正确的地方,欢迎提出,感激...

如何开始学习JAVA编程?

#记录我的9月生活#...

java后端开发需要学什么?

Java属于后端开发中最常见的语言之一,Java这种语言的体系比较中立,而且具备了构建多线程的能力,在许多大型互联网平台Java的应用范围特别广泛。  java后端主要涉及到如下4个技术:  第一、S...

细思极恐:你真的会写Java吗?

导语自2013年毕业后,今年已经是我工作的第4个年头了,总在做java相关的工作,终于有时间坐下来,写一篇关于java写法的一篇文章,来探讨一下如果你真的是一个java程序员,那你真的会写java吗?...

七年Java开发的一路辛酸史:分享面试京东、阿里、美团后的心得

前言我觉得有一个能够找一份大厂的offer的想法,这是很正常的,这并不是我们的饭后谈资而是每个技术人的追求。像阿里、腾讯、美团、字节跳动、京东等等的技术氛围与技术规范度还是要明显优于一些创业型公司...

我把Java基础编程及思维导图整理的超级详细,小白都能看懂

Java基础编程及其思维导图目录:Java学习导图一、Java基本语法1.关键字与标识符2.变量分类3.运算符4.流程控制二、数组1.数组概述2.一维数组3.二维数组4.数组常见算法5....

Java 开发中的 9 个实用技巧:案例详解

Java开发中,总有一些技巧能够帮助我们提高代码质量和开发效率。下面,我们来分享9个Java技巧,每个技巧都附上实际案例,帮助你在工作中立刻应用。1.合理使用final关键字...

Java 20年,以后将往哪儿走?

在今年的Java20周年的庆祝大会中,JavaOne2015的中心议题是“Java的20年”。甲骨文公司Java平台软件开发部的副总裁GeorgesSaab的主题演讲就将关注点放在了java...

推荐1个java快速开发项目,让你接私活不用愁

??大家好,我是小编南风吹,每天推荐一个小工具/源码,装满你的收藏夹,让你轻松节省开发效率,实现不加班不熬夜不掉头发!...

教你用Java开发一个简单的JVM

一、前言几年前,接到一个开发任务:用Java开发能运行Java智能合约的虚拟机。在开发Java智能合约时,只能使用智能合约SDK提供的类和一些Java常用类(8种基本数据类型包装类;String、Bi...

java实战教程(一)软件开发流程&开发模式

这里小编为了方便处于不同学习阶段的童鞋,准备了三个系列的文章,java系列教程、java实战教程、java进阶教程,对于刚入坑的童鞋,可以先按照这三个系列教程一步步的了解,循序渐进,java实战系列教...

Java 核心技术之入门指南:全面解析Java概述

大家好,这里是Java码牛!Java核心技术入门:全面解析Java概述一、引言Java,作为一门在当今信息技术领域中被广泛应用于企业级开发的主流编程语言,其核心技术的精准掌握对于众多开发者而言,具有...

小白如何轻松上手Java开发?

Java,这款流行的编程语言,被广大开发者所钟爱。但对于初学者来说,如何入门确实是一个大问题。尤其对于毫无经验的小白,从何处开始、如何推进,都是关键。本文将带你走进Java的世界,为你揭示从零到一的进...

初学Java应该知道的知识点:Java的程序开发是什么?

Java的程序开发是什么呢?下面和千锋广州小编一起来看看吧!一般来说,Java的程序开发包括三个步骤:编写程序,编译程序,运行程序编写程序——Java源代码,.Java文件编译程序——Javac用来进...

厉害了!全靠经典之作-Java编程思想,把小白教的明明白白

今天我们来聊聊这本《Java编程思想》从我学习Java的经验来看,《ThinkinginJava》是讲解Java编程的最佳书籍!  这本书不仅详细地介绍Java语法、知识点、API类库使用,更...