【JavaSE学习笔记】Java中的多态及其引出的Upcast和Downcast问题

2023-11-19

JavaSE学习笔记:JAVA中的多态及其引出的Upcast和Downcast



前言

最新在学习JAVASE的时候碰到了JAVA特性之一:多态,并且对多态引出的类型转换问题(upcast和downcast)很迷茫,故自己手写了代码进行测试验证,在此记录一下。


一、JAVA中的多态

1.多态是同一个行为具有多个不同表现形式或形态的能力。
2.多态就是同一个接口,使用不同的实例而执行不同操作:
想象这样一个场景下:
在银行进行创建一个新的账户时,银行可能需要登记下持卡人的性别,但是在进行创建之前即我们写下创建账户的代码时,我们是无法确定持卡人的性别的,但是有一点可以确定的是持卡人不论男人(Man)还是女人(Woman)他们都是属于人(Person)这一类的,在没有JAVA多态这一性质时我们可能需要分别针对男性和女性这两种性别去写两个创建账户的方法。而JAVA中的多态可以解决这个问题,即我们只需要将持卡人所属的基类传入我们的函数即可。

// 1.
// 创建账户的方法,形参为持卡人,返回一个账户
public Account creatCount(持卡人){
	....
}
// 2.
// 在没有多态特性时,需要针对性别写下两个方法
public Account creatCount(Man m){
	....
}
public Account creatCount(Woman w){
	....
}
// 3.
// 在有多态特性时,只需将Man、Woman所属的基类Person传入即可:
public Account creatCount(Person p){
	....
}

可见JAVA中的多态特性可以减少代码的编写,避免同一个方法的重载,提高代码复用性。

二、Upcast & Downcast

1.我们可以将一个衍生类引用转换为其基类引用,这叫做向上转换(upcast)或者宽松转换。
2.将一个基类引用向下转型(downcast)成为衍生类的引用,但要求该基类引用所指向的对象


下面代码中:

  • 创建了一个基类Animal,类Cat和类Dog继承类Animal,并对Animal类中的getName、eat、shout方法进行重写;

  • 类Cat和类Dog中分别有一个自己独有的方法:cute方法和watchDoor方法;

  • 创建了Test类进行测试,其中Test类中出了main方法,还包括一个打印动物基本信息的方法:printInfo;


package test;

public class Test{
    public static void main(String[] args){

        Test t = new Test();
        // upcast
        Animal a = new Cat("咪咪");
        Animal b = new Dog("旺财");

        // a is a cat
        t.printInfo(a);
        a.eat();
        a.shout();

        System.out.println("*************");

        // b is a dog
        t.printInfo(b);
        b.getName();
        b.eat();
        b.shout();

        System.out.println("*************");

        // downcast
        Cat c = (Cat) a;
        Dog d = (Dog) b;
        // 调用Cat和Dog中各自特有的方法
        c.Cute();
        d.watchDoor();


    }

    public void printInfo(Animal animal){
        System.out.println("我是 " + animal.getKind() + ", 我的名字叫 " + animal.getName());
    }
}
abstract class Animal{

    private String kind; // 动物的种类

    public Animal(String kind){
        this.kind = kind;
    }

    public String getKind() {
        return kind;
    }

    public abstract String getName();
    public abstract void eat();
    public abstract void shout();
}

class Cat extends Animal{
    private String name; // 动物的名字

    public Cat(String name){
        super("cat");
        this.name = name;
    }

    // 重写Animal类中的getName方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 重写Anmial类中的eat方法
    public void eat(){
        System.out.println("cat eat fish");
    }

    // 重写Anmial类中的shout方法
    public void shout(){
        System.out.println("喵喵喵~");
    }

    // Cat类中独有的方法:可爱
    public void Cute(){
        System.out.println("我很可爱~");
    }
}

class Dog extends Animal{
    private String name; // 动物的名字

    public Dog(String name){
        super("dog");
        this.name = name;
    }

    // 重写Animal类中的getName方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 重写Anmial类中的eat方法
    public void eat(){
        System.out.println("dog eat bone");
    }

    // 重写Anmial类中的shout方法
    public void shout(){
        System.out.println("汪汪汪!");
    }

    // dog类中独有的方法:看门
    public void watchDoor(){
        System.out.println("我是dog可以看门!");
    }
}

程序运行结果:
我是 cat, 我的名字叫 咪咪
cat eat fish
喵喵喵~
*************
我是 dog, 我的名字叫 旺财
dog eat bone
汪汪汪!
*************
我很可爱~
我是dog可以看门!

下面结合代码对upcast和downcast分别进行解析:

  1. upcast: 在main方法中我们创建了两个animal类的实例a和b,其中a指向一个cat类,b指向一个dog类,当我们想打印a和b的基本信息时调用printInfo方法:public void printInfo(Animal animal),具体调用代码:t.printInfo(a); t.printInfo(b);可见printInfo方法需要传入的参数是Animal类的,而我们的a和b是满足条件的,分别打印出了猫和狗的信息,即说明在调用方法是使用的是子类中的方法。此外a.eat(); a.shout();以及b.eat();b.shout();也分别打印出了猫和狗的对应信息;
  2. downcast:Cat c = (Cat) a;Dog d = (Dog) b;是downcast的体现,即将指向子类的基类强制转换为原来的子类,此时便可调用子类中独有的方法:c.Cute();d.watchDoor();而a和b是无法调用cat和dog类中独有的方法的,即a和b只能调用基类Animal中的方法,当调用子类的方法时运行会报错,例如a调用Cat类中的独有方法cute,运行报错,具体如下图所示:a调用Cat类中的独有方法cute,运行报错

三、总结

1.面对多态时,明确“编译看左,运行看右”原则;
2.多态特性可以可以减少代码的编写,避免同一个方法的重载,提高代码通用性;
3.明确只有进行downcast后,才可调用子类中独有的方法;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【JavaSE学习笔记】Java中的多态及其引出的Upcast和Downcast问题 的相关文章

  • 在这个 Spring MVC 展示示例中如何使用 @RequestAttribute 和 @ModelAttribute 注释?

    我对 Spring MVC 还很陌生 这段时间我正在学习Spring MVC 展示 https github com spring projects spring mvc showcase可从 STS 仪表板下载示例 我在理解此示例中如何处
  • ClientRequestFactory RestEasy 已弃用...还有其他 RestEasy 替代方案吗?

    我需要使用其他人创建的 RestService 的接口来创建轻松的客户端 这工作很好 除了一件事 当我从rest easy 2 3 5 Final更新到resteasy 3 0 x时 Client RequestFactory类看起来像 D
  • cucumber.json 报告被重新运行场景报告覆盖

    我有一个具有相同技术堆栈 JAVA1 8 Cucumber JVM JUnit Maven 的 UI 测试项目和一个 API 测试项目 这两个项目都向我展示了这个问题 可能是因为两者都存在相同的依赖关系集 我使用了使用 maven sure
  • 使用 Firebase Java API 检索/格式化数据的最佳方式

    我在用着Firebase用于数据存储Android项目 并使用Firebase Java API来处理数据 不过 我不确定我是否尽可能高效地完成此操作 并且我希望获得一些有关检索和格式化数据的最佳实践的建议 我的Firebase存储库看起来
  • Spring Kafka - 为任何主题的分区消耗最后 N 条消息

    我正在尝试读取请求的卡夫卡消息数 对于非事务性消息 我们将从 endoffset N 对于 M 个分区 开始轮询并收集当前偏移量小于每个分区的结束偏移量的消息 对于幂等 事务消息 我们必须考虑事务标记 重复消息 这意味着偏移量将不连续 在这
  • Appengine - 隐藏文件夹的部署

    为了验证 SSL 证书 我需要将包含一些文件的隐藏文件夹 well known 上传到我的应用程序 我正在使用 eclipse 部署 java 应用程序 但 appengine 上的应用程序未收到这些文件 我猜他们被过滤掉了 我尝试将隐藏文
  • 如何使用 Java2D 创建硬件加速图像?

    我正在尝试创建一个快速图像生成器 它可以执行大量 2d 转换和形状渲染 因此我尝试使用 BufferedImage 然后获取 Graphics2D 对象来执行所有绘图 我现在主要关心的是 make 速度非常快 所以我创建一个像这样的 Buf
  • JConsole主类

    我正在尝试使用其 Main 类从命令行启动 JConsole 我提取了 jconsole jar 的内容 在 MANIFEST MF 中我可以看到 Main Class sun tools jconsole JConsole 所以我尝试运行
  • 是否可以将 BitmapDescriptor 转换为 Bitmap?

    我需要将 BitmapDescriptor 转换为 Bitmap 我可以使用以下代码将位图转换为 BitmapDescriptor BitmapDescriptor bd BitmapDescriptorFactory fromBitmap
  • 在java中迭代日期

    我需要遍历一系列日期 不确定如何在 for 循环中获取第二天 我在用java util Date So plusDays 1 不能在 for 循环中用于获取下一个日期 Used date1 new Date date1 getTime 10
  • 为什么在java中加载JNI是在静态初始化程序中完成的?

    在许多使用 JNI 的示例中 我看到类似以下内容 class SampleClass static System loadLibrary somelib 这种特殊语法的目的是什么 为什么使用这个 而不仅仅是在类构造函数或类似的东西中 我想你
  • 如何在 TestNG 报告中包含 Log4j2 消息

    我希望在所有测试用例的 TestNG 报告中提供 Log4j2 日志记录信息 TestNG 使用一个名为 Reporter java 的特殊记录器类来跟踪日志输出并将其保存在其结果 XML 中 在 log4j 中 可以简单地创建一个路由到
  • Java 线程 JavaDoc

    我编写了一个只能在特定线程上调用的方法 是否应该将标准注释或注释添加到方法的 javadoc 中来表示这一点 不知道有任何这样的标准注释 Java 并发实践 http www javaconcurrencyinpractice com 在第
  • android 中的 lang.NumberFormatException

    我有以下代码 除了在后台线程中从数据库读取一些值并使用这些值之外什么也不做 我使用 jar 绘制折线图 对于我用于每个数组值的折线图 问题是第三个我传递给绘制 LineChart 的构造函数的参数是 float float viteza S
  • 参数列表中的“...”是什么意思? doInBackground(字符串...参数)

    我不明白那个语法 尝试用谷歌搜索各种单词加上 是没有用的 它被称为varargs http java sun com j2se 1 5 0 docs guide language varargs html 这个事实应该产生更好的谷歌结果 h
  • C中使用JNI从对象获取对象

    public class Student private People people private Result result private int amount 这是 Java 中类的示例 在C中 我试图获取 学生 中的 人 但失败了
  • Java中精确的时间测量

    Java 提供了两种获取当前时间的方法 System nanoTime and System currentTimeMillis 第一个给出的结果以纳秒为单位 但实际精度比这要差得多 许多微秒 JVM 是否已经为每台特定机器提供了最佳的价值
  • 如何使用属性文件在log4j2中创建多个日志文件?

    我正在使用 property 文件在特定路径中创建日志文件 但我正在使用它创建单个文件 以下是我的属性文件代码 status error dest err name PropertiesConfig property filepath ap
  • 获取给定字符串日期中该月的最后一天

    我的输入字符串日期如下 String date 1 13 2012 我得到的月份如下 SimpleDateFormat dateFormat new SimpleDateFormat MM dd yyyy Date convertedDat
  • Java 中的下载管理器 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我需要通过 FTP HTTP 从 Java 获取几个大文件 几个演出 有现成的库 java 命令行工具

随机推荐

  • windows下使用CMake构建工程:cmake-gui+Visual Studio

    文件结构 在工程目录下构建目录src thirdparty build src 存放自己写的源代码文件 thirdparty 存放使用的第三方库 build 存放编译时生成的文件 因为很多很杂乱 所以单独目录存放 保持项目文件夹整洁 在bu
  • 核方法、核密度估计与核函数

    核方法 核密度估计与核函数 核方法 Kernel Methods 是一类常用于机器学习和统计学中的非参数方法 主要用于特征转换和模式识别 核方法通过将数据映射到高维特征空间 使得线性不可分的问题在高维空间中变得线性可分 其中 核函数 Ker
  • 未来展望——学习规划

    不知不觉就来到了研二 找工作和科研两座大山压在身上 我的专业是机械设计及理论 主要研究的方向是新能源汽车电驱动系统设计 平时主要的工作就是先在Matlab Simulink里搭建出PMSM的控制模型 观测器模型等 再将其转化为C代码烧录到D
  • 什么是GPT?初学者如何使用GPT?GPT入门学习

    灵魂发问 GPT科研中没有那么神 GPT账号不能轻松使用 GPT怎样才融合到我的科研中 别人用的非常酷 为什么我用的不行 让GPT成为您的科研加速器 GPT对于每个科研人员已经成为不可或缺的辅助工具 不同的研究领域和项目具有不同的需求 如在
  • tp-wr886n虚拟服务器在哪,新版TP-LINK TL-WR886N默认登录地址是多少?【图解】

    新版TP LINK TL WR886N默认登录地址是多少 问 最近刚买的普联TP LINK新款无线路由器 请问tplink TL WR886N默认登录地址是多少 想要登录这台TL WR886N不知道管理IP地址如何登录呢 答 TP LINK
  • iOS进阶_kvc使用注意事项

    细节1 我们在项目中使用kvc 在设置model属性的时候 注意尽量不要使用基本数据类型 实例 数据模拟 注意age是null类型的 Person h import
  • robotframework安装使用

    一 Robot Framework 介绍 Robot Framework 是一款基于 Python 的功能自动化测试框架 它具备良好的可扩展性 支持关键字驱动 可以同时测试多种类型的客户端或者接口 可以进行分布式测试执行 主要用于轮次很多的
  • 解决问题方法汇总:ROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysq

    var lib mysql mysql sock 这个目录是my cnf中配置的 连接localhost通常通过一个Unix域套接字文件进行 即这个mysql sock文件 如果套接字文件被删除了 本地客户就不能连接 systemctl s
  • el-upload上传阿里云(oss上传)

    oss上传 在你的项目安装oss npm install ali oss save 初始化oss 配置文件 新建一个js文件 内容如下 代表你所申请的参数 问运维要 let OSS require ali oss export let cl
  • Oracle函数集锦

    一 case when then 用法 case具有两种格式 简单case函数和case搜索函数 简单case函数 case sex when 1 then 男 when 2 then 女 else 其他 end case搜索函数 case
  • OpenGL GLFW入门篇 - 画矩形2

    上一篇介绍了如何渲染矩形 这一篇介绍如何将叠加的部分透明显示 效果图 主体代码 void DrawRectangle void GLfloat xl yt xr yb w h glPushMatrix glLoadIdentity glTr
  • [vue3]用element封装一个抽屉组件

    需求 因为抽屉组件在后台管理系统是非常常见的 那么封装起来怎么样 可以传入标题 size 提交按钮的文字 传入部分即便超出范围也不会挤掉下面的按钮 会出现滚动条 如图
  • 文件目录和目录文件的作用区别和联系 & C语言文件相关操作 FILE用法

    一 文件目录和目录文件的作用区别和联系 1 他们各自的概念和联系 文件目录 把所有的FCB组织在一起 就构成了文件目录 即文件控制块的有序集合 FCB 为了能对一个文件进行正确的存取 操作系统必须为文件设置用于描述和控制文件的数据结构 称之
  • setlocale()/_wsetlocale()函数的使用

    在C运行库提供的多字节字符 宽字符转换函数 mbstowcs wcstombs 中 需要用到全局变量locale locale encoding 以指定多字节字符的编码类型 1 功能 用来定义全局变量 locale locale encod
  • linux进阶52——pthread_cond_t

    1 概念 条件变量是线程可用的另一种同步机制 条件变量给多个线程提供了一个会合的场所 条件变量与互斥量一起使用时 允许线程以无竞争的方式等待特定的条件发生 条件变量是线程中的东西 就是等待某一条件的发生 和信号一样 2 使用场景 条件变量要
  • Elasticsearch实战(二十二)---ES数据建模与Mysql对比 一对一模型

    Elasticsearch实战 ES数据建模与Mysql对比实现 一对一模型 文章目录 Elasticsearch实战 ES数据建模与Mysql对比实现 一对一模型 1 一对一 模型 1 1 Mysql建模 1 2 Index ES 模型
  • JetBrains IDE 全新UI申请体验

    JetBrains 宣布为其 IDE 系列产品更新默认 UI 申请 目前需要去官网申请才能获得试用 申请地址 https www jetbrains com lp intellij new ui preview 试用资格 在官网申请之后 就
  • 安装或者升级cmake版本

    1 cmake至少需要3 20 的版本 可以去官网 https cmake org files 下载 也可以通过wget下载并解压 如果下载很慢或打不开官网 可评论留邮箱发你 wget 下载 wget https cmake org fil
  • jq 用val()获取input的值无效

    用id获取input标签 取不到该input的value值 用改标签的name属性就可以 4个下面这种input 懒得复制了 就贴一个
  • 【JavaSE学习笔记】Java中的多态及其引出的Upcast和Downcast问题

    JavaSE学习笔记 JAVA中的多态及其引出的Upcast和Downcast 文章目录 JavaSE学习笔记 JAVA中的多态及其引出的Upcast和Downcast 前言 一 JAVA中的多态 二 Upcast Downcast 三 总