这篇文章贯穿游戏中的一些功能带你掌握多态的使用

为什么要使用多态

在一款对战类游戏中(如有雷同纯属巧合),有两个不同的法师英雄:小乔、妲己。

两个法师英雄的都有攻击的方法,小乔的攻击伤害为10,消耗魔法20。妲己的攻击伤害为15,消耗魔法30。玩家可以操作两个英雄进行攻击,下面看看实现的代码。

父类-英雄:whyusepolymorphic.Hero.java

package whyusepolymorphic;

public class Hero {
private int magicPoint;//魔法值
private int hurt;//伤害
private String name;//姓名 public Hero(int magicPoint, int hurt, String name) {
super();
this.magicPoint = magicPoint;
this.hurt = hurt;
this.name = name;
} public int getMagicPoint() {
return magicPoint;
} public void setMagicPoint(int magicPoint) {
this.magicPoint = magicPoint;
} //省略属性的 getter 和 setter 方法
}

子类-小乔:whyusepolymorphic.LittleJoe.java

package whyusepolymorphic;

public class LittleJoe extends Hero {

	public LittleJoe(int magicPoint, int hurt, String name) {
super(magicPoint, hurt, name);
} //攻击的方法
public void attack() {
System.out.println(this.getName()+" 发动攻击,伤害为:"+this.getHurt()
+"。消耗 20的魔法值");
this.setMagicPoint(getMagicPoint()-20);//魔法值-20
} }

子类-妲己:whyusepolymorphic.Daji.java

package whyusepolymorphic;

public class Daji extends Hero{

	public Daji(int magicPoint, int hurt, String name) {
super(magicPoint, hurt, name);
} public void attack() {
System.out.println(this.getName()+" 发动攻击,伤害为:"+this.getHurt()
+"。消耗 30的魔法值");
this.setMagicPoint(getMagicPoint()-30);//魔法值-30
}
}

玩家:whyusepolymorphic.Player.java

package whyusepolymorphic;

public class Player {
public void play(LittleJoe littleJoe) {
littleJoe.attack();
}
public void play(Daji daji) {
daji.attack();
}
}

上面代码完整的实现了要求中的功能,那我们知道英雄不可能就这几个,后期如果添加新的魔法英雄,伤害不一样,怎么办?

我们可以添加新的类,实现攻击的方法,修改玩家类添加操作英雄的方法。这个方式可以完成 Hero 扩展的需求,但是后面有更多的 Hero 添加进来,我们维护起来就不是那么方便了。

研究上面的代码我们发现,Player 类中的 play 方法的参数都是 Hero 类的子类,能否使用一个 play(Hero hero) 方法操作所有的英雄?使用多态就能够实现这种优化设计。

什么是多态

简明扼要,多态就是多种形态。在自然界中碳的多态就有石墨、钻石等,剪这个动作就有剪纸、剪头发等。同一个操作,由于条件的不同,产生的结果也不同。

那么在程序中的多态,就是指同一个引用类型,使用不同的实例而执行不同的操作(父类引用指定子类对象 Hero h=new Daji();)。

如何实现多态

实现多态的步骤:

1.编写具有继承关系的父类和子类

2.子类重写父类方法

3.使用父类的引用指向子类的对象

父类作为方法形参实现多态

使用多态优化上面代码

修改 Hero.java 添加攻击的方法

package whyusepolymorphic;

public class Hero {
//省略属性和构造方法 //攻击的方法
public void attack() {
System.out.println(this.getName()+" 发动攻击,伤害为:"+this.getHurt()
+"。消耗 20的魔法值");
this.setMagicPoint(getMagicPoint()-20);//魔法值-20
}
//省略 getter 和 setter 方法
}

两个子类不用修改

修改玩家类 Player.java 将 play方法的参数设为父类

package whyusepolymorphic;

public class Player {
public void play(Hero hero) {
hero.attack();
}
}

修改测试类

package whyusepolymorphic;

public class TestPlay {
public static void main(String[] args) {
Player p=new Player();
Hero daji=new Daji(100,15,"妲己");
p.play(daji);
System.out.println(daji.getName()+" 剩余魔法:"+daji.getMagicPoint());
Hero littleJoe=new LittleJoe(100,10,"小乔");
p.play(littleJoe);
System.out.println(littleJoe.getName()+" 剩余魔法:"+littleJoe.getMagicPoint());
}
}

父类作为返回值实现多态

玩家购买英雄使用多态实现,购买的方法有返回值,返回购买后的英雄,父类作为返回值实现这个功能。

修改玩家类 Player.java 添加获取英雄的方法

package whyusepolymorphic;

public class Player {
public void play(Hero hero) {
hero.attack();
} public Hero getHero(int id) {
if(1==id) {
return new Daji(100,15,"妲己");
}else if(2==id){
return new LittleJoe(100,10,"小乔");
}else {
System.out.println("没有这个英雄");
return null;
}
}
}

测试类

package whyusepolymorphic;

import java.util.Scanner;

public class TestPlay {
public static void main(String[] args) {
Player p=new Player();
System.out.println("欢迎来到英雄商店,请选择要购买的英雄:1.妲己2.小乔");
Scanner input=new Scanner(System.in);
int id=input.nextInt();
Hero h=p.getHero(id);
if(null!=h) {
h.attack();
}
}
}

父类到子类的转换

如果子类中有一些子类特有的方法,父类引用不能调用子类的特有的方法。

向 Daji.java 中添加一个方法 queenWorship

package whyusepolymorphic;

public class Daji extends Hero{
//省略构造方法及之前其他方法
public void queenWorship() {
System.out.println("释放大招:女王崇拜");
}
}

向 LittleJoe.java 中添加一个方法 dazzlingStar

package whyusepolymorphic;

public class LittleJoe extends Hero {
//省略构造方法及之前其他方法
public void dazzlingStar() {
System.out.println("释放大招:星华缭乱");
}
}

在 Player.java 中添加 bigMove 方法

package whyusepolymorphic;

public class Player {
//省略构造方法及之前其他方法
public void bigMove(Hero hero) {
hero.dazzlingStar();
}
}

发现代码 hero.dazzlingStar(); 报错

那么这个时候就需要将父类转换为子类(强制类型转换)

Hero joe=new LittleJoe(100,10,"小乔");
Daji daji=(Daji) joe;

但是直接这样写也会报错,用 instanceof 运算符可以保证不会转换错误

语法:

对象 instanceof 类或接口

instanceof通常和强制类型转换结合使用

修改 Player.java 中的 bigMove 方法

public void bigMove(Hero hero) {
if (hero instanceof Daji) {
((Daji)hero).queenWorship();
}else if(hero instanceof LittleJoe) {
((LittleJoe)hero).dazzlingStar();
}
}

在 main 方法中编写测试代码

Player p=new Player();
p.bigMove(new LittleJoe(100,10,"小乔"));
p.bigMove(new Daji(100,15,"妲己"));

本人能力和水平有限,欢迎在文章下方给建议

搜索关注公众号「享智同行」,第一时间获取技术干货

Java入门系列-17-多态的更多相关文章

  1. Java 集合系列 17 TreeSet

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  2. java io系列17之 System.out.println("hello world")原理

    我们初学java的第一个程序是"hello world" public class HelloWorld { public static void main(String[] ar ...

  3. Java入门系列-26-JDBC

    认识 JDBC JDBC (Java DataBase Connectivity) 是 Java 数据库连接技术的简称,用于连接常用数据库. Sun 公司提供了 JDBC API ,供程序员调用接口和 ...

  4. Java入门系列-19-泛型集合

    集合 如何存储每天的新闻信息?每天的新闻总数是不固定的,太少浪费空间,太多空间不足. 如果并不知道程序运行时会需要多少对象,或者需要更复杂方式存储对象,可以使用Java集合框架. Java 集合框架提 ...

  5. Java入门系列(三)面向对象三大特性之封装、继承、多态

    面向对象综述 封装 封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,或者叫接口. 有了封装,就可以明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者:而外部调用者也可以知道 ...

  6. 夯实Java基础系列17:一文搞懂Java多线程使用方式、实现原理以及常见面试题

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  7. Java入门系列之包装类(四)

    前言 上一节我们讲解了StringBuilder VS StringBuffer以及二者区别,本节我们来讲解包装类. 包装类 我们知道在Java中有8中基本数据类型,分为数值类型:byte.short ...

  8. Java入门系列:实例讲解ArrayList用法

    本文通过实例讲解Java中如何使用ArrayList类. Java.util.ArrayList类是一个动态数组类型,也就是说,ArrayList对象既有数组的特征,也有链表的特征.可以随时从链表中添 ...

  9. Java入门系列-18-抽象类和接口

    抽象类 在第16节继承中,有父类 People People people=new People(); people.sayHi(); 实例化People是没有意义的,因为"人"是 ...

随机推荐

  1. CLR via C# 读书笔记-21.托管堆和垃圾回收

    前言 近段时间工作需要用到了这块知识,遂加急补了一下基础,CLR中这一章节反复看了好多遍,得知一二,便记录下来,给自己做一个学习记录,也希望不对地方能够得到补充指点. 1,.托管代码和非托管代码的区别 ...

  2. “全栈2019”Java第十九章:关系运算符、条件运算符和三元运算符

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  3. 面向对象中的__slots__

    类中的__slots__ 正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性. 而要限制class的属性就需要用到__sl ...

  4. 初探 模拟退火算法 POJ2420 HDU1109

    模拟退火算法来源于固体退火原理,更多的化学物理公式等等这里不再废话,我们直接这么来看 模拟退火算法简而言之就是一种暴力搜索算法,用来在一定概率下查找全局最优解 找的过程和固体退火原理有所联系,一般来讲 ...

  5. MVC模式学习--雇员管理系统项目开发

    1, 项目开发,使用原型开发, ① 开发流程: 需求分析->设计阶段->编码阶段->测试阶段->发布阶段/维护阶段 需求阶段:PM/项目经理 对客户 设计阶段:技术人员(架构师 ...

  6. NFS共享服务

    一.网络文件系统共享服务 NFS( Network File System,网络文件系统 )是一种基于TCP/IP传输的网络文件系统协议,最初由SUN公司开发,通过使用NFS协议,客户机可以像访问本地 ...

  7. UIViewContentMode-

    图片很小,frame很大 图片很大,frame很小 UIViewContentModeScaleToFill, UIViewContentModeScaleAspectFit, UIViewConte ...

  8. 2016级算法第二次上机-D.Bamboo的饼干

    Bamboo的饼干 分析 从两个数组中各取一个数,使两者相加等于给定值.要注意去重和排序 难度不大,方法很多,基本只要不大于O(n^2 ) 的都可以过.本意想考察二分搜索 还可以借助stl中的map, ...

  9. 自己写的第一个Schema文件

    <Schema name="FinSchema" description="财务模式" measuresCaption="财务模式"& ...

  10. 2019年华南理工大学程序设计竞赛(春季赛) K Parco_Love_String(后缀自动机)找两个串的相同字串有多少

    https://ac.nowcoder.com/acm/contest/625/K 题意: 给出Q 个询问 i , 求 s[0..i-1] 与 s[i...len-1] 有多少相同的字串 分析: 给出 ...