java多态/类的组合2022023

news2024/11/17 8:20:27

多态
Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态(Polymorphism)。其实就是子类的对象赋值给父类的引用变量。

举个代表性的例子:
父类Parent有A方法,B方法,成员变量X,子类Sub继承父类,重写B方法,自己有C方法,成员变量X,然后
Parent parent=new Sub();
Parent。A() 当调用该引用变量的A方法则正常会走父类的A方法;
Parent。B() 当调用该引用变量的B方法(Parent类中定义了该方法,子类Sub中覆盖了父类的该方法)时,实际执行的是子类Sub类中覆盖后的B方法,这就出现多态了。
Parent。C() 当调用该引用变量的C方法时,父类中没有,则报错;虽然parent引用变量实际上确实包含C方法(例如,可以通过反射来执行该方法),但因为它的编译时类型为
Parent,因此编译时无法调用C方法。通过引用变量来访问其包含的实例变量时,系统总是试图访问它编译时类型所定义的成员变量,而不是它运行时类型所定义的成员变量。引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法。因此编写Java代码时,引用变量只能调用声明该变量时所用类里包含的方法。例如, 通过Object p=new Person()代码定义一个变量p,则这个p只能调用Object类的方法,而不能调用Person类里定义的方法。综合起来说,在编写Java程序时,引用变量只能调用它编译时类型的方法,而不能调用它运行时类型的方法,即使它实际所引用的对象确实包含该方法。如果需要让这个引用变量调用它运行时类型的方法,则必须把它强制类型转换成运行时类型,强制类型转换需要借助于类型转换运算符。

重点:
与方法不同的是,对象的实例变量则不具备多态性。比如上面的parent引用变量,程序中输出它的X实例变量时,并不是输出Sub类里定义的实例变量,而是输出Parent类的实例变量。

又引申出来了新的问题:强制类型转换
语法是 :(type)variable,这种用法可以将variable变量转换成一个type类型的变量。前面在介绍基本类型的强制类型转换时,已经看到了使用这种类型转换运算符的用法,类型转换运算符可以将一个基本类型变量转换成另一个类型。
除此之外,这个类型转换运算符还可以将一个引用类型变量转换成其子类类型。这种强制类型转换不是万能的,当进行强制类型转换时需要注意:基本类型之间的转换只能在数值类型之间进行,这里所说的数值类型包括整数型、字符型和浮点型。但数值类型和布尔类型之间不能进行类型转换。
引用类型之间的转换只能在具有继承关系的两个类型之间进行,如果是两个没有任何继承关系的类型,则无法进行类型转换,否则编译时就会出现错误。如果试图把一个父类实例转换 成子类类型,则这个对象必须实际上是子类实例才行(即编译时类型为父类类型,而运行时类型是子类类型),否则将在运行时引发ClassCastException异常。
考虑到进行强制类型转换时可能出现异常,因此进行类型转换之前应先通过instanceof运算符来判断是否可以成功转换。先判断:
在这里插入图片描述
注意:
当把子类对象赋值给父类引用变量时,被称为向上转型upcasting),这种转型总是可以成功的,这也从另一个侧面证实了子类是一种特殊的父类。这种转型只是表明这个引用变量的编译时类型是父类,但实际执行它的方法时,依然表现出子类对象的行为方式。但把一个父类对象赋给子类引用变量时,就需要进行强制类型转换,而且还可能在运行时产生ClassCastException异常,使用instanceof运算符可以让强制类型转换更安全。instanceof和类型转换运算符一样,都是Java提供的运算符,与+、-等算术运算符的用法大致相似。
instanceof运算符的前一个操作数通常是一个引用类型变量,后 一个操作数通常是一个类(也可以是接口,可以把接口理解成一种特殊的类),它用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是,则返回true,否则返回false。
在使用instanceof运算符时需要注意:instanceof运算符前面操作数的编译时类型要么与后面的类相同,要么与后面的类具有父子继承关系,否则会引起编译错误。
instanceof运算符的作用是:
在进行强制类型转换之前,首先判断前一个对象是否是后一个类的实例,是否可以成功转换,
instanceof和(type)是Java提供的两个相关的运算符,通常先用instanceof判断一个对象是否可以强制类型转换,然后再使用(type)运算符进行强制类型转换,从而保证程序不会出现错误。

再想想:利用继承和多态,其实会破坏封装,比如
Animal a = new Dog();
a.eat() ;
如果eat方法在Dog类中被重写,下面a.eat()就是调用的Dog中的;也就是意味着父类的eat()被恶意篡改了!!!

为了保证父类有良好的封装性,不会被子类随意改变,设计父类通常应该遵循如下规则。
1.尽量隐藏父类的内部数据。尽量把父类的所有成员变量都设置成private访问类型,不要让子类直接访问父类的成员变量。
2.不要让子类可以随意访问、修改父类的方法。父类中那些仅为辅助其他的工具方法,应该使用private访问控制符修饰,让子类无法访问该方法;如果父类中的方法需要被外部类调用,则必须以public修饰,但又不希望子类重写该方法,可以使用final修饰符来修饰该方 法;如果希望父类的某个方法只是被子类重写,但不希望被其他类自由访问,则可以使用protected来修饰该方法。
3.尽量不要在父类构造器中调用将要被子类重写的方法。会导致调用混乱,空指针等问题。

那么怎么将类变成最终类呢?
1.如果想把某些类设置成最终类,即不能被当成父类不能被继承不能被调用构造器,则可以使用final修饰这个类 , 例如 JDK 提 供 的 java.lang.String 类和java.lang.System类。
2.如果想当父类,但是不想让构造器被随便调用,则使用private修饰这个类的所有构造器,从而保证子类无法调用该类的构造器,也就无法继承该类(其实也当不成父类)。但是如果还想产生实例对象呢?对于把所有的构造器都使用private修饰的父类而言,可另外提供一个静态方法,用于创建该类的实例。

类的继承不是随随便便的
到底何时需要从父类派生新的子类呢?不仅需要保证子类是一种特殊的父类,而且需要具备以下两个条件之一。
1.子类需要额外增加成员变量,而不仅仅是变量值的改变。例如从Person类派生出 Student子类 , Person 类里没有提供grade(年级)成员变量,而Student类需要grade成员变量来保存Student对象就读的年级,这种父类到子类的派生,就符合Java继承的前提。
2.子类需要增加自己独有的行为方式(包括增加新的方法或重写父类的方法)。例如从 Person类派生出Teacher 类 , 其中Teacher类需要增加一个teaching()方法,该方法用于描述Teacher对象独有的行为方式:教学。

终于明白啥叫 类的组合
其实就是之前一直觉得有点那个的点,就是一个类实际上也是类型,就可以当成int这种使用,这就叫做组合,组合是把旧类对象作为新类的成员变量组合进来,用以实现新类的功能, 用户看到的是新类的方法,而不能看到被组合对象的方法。
在这里插入图片描述
到底该用继承?还是该用组合呢?
继承是对已有的类做一番改造,以此获得一个特殊的版本。简而言之,就是将一个较为抽象的类改造成能适用于某些特定需求的类。因此,对于上面的Wolf和Animal的关系,使用继承更能表达其现实意义。用一个动物来合成一匹狼毫无意义:狼并不是由动物组成的。
反之,如果两个类之间有明确的整体、部分的关系,例如Person类需要复用Arm类的方法(Person对象由Arm对象组合而成),此时就应该采用组合关系来实现复用,把Arm作为Person类的组合成员变量,借助于Arm的方法来实现Person的方法,这是一个不错的选择。
总之,继承要表达的是一种“是(is-a)”的关系,而组合表达的是“有(has-a)”的关系。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode刷题复盘笔记—一文搞懂贪心算法之55. 跳跃游戏问题(贪心算法系列第四篇)

今日主要总结一下可以使用贪心算法解决的一道题目,55. 跳跃游戏 题目:55. 跳跃游戏 Leetcode题目地址 题目描述: 给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。 数组中的每个元素代表你在该位置可以跳跃的最大长…

Python流程控制语句之选择语句

前言 在生活中,我们总是要做出许多选择,程序也是一样。比如下面的例子: 如果输入的用户名和密码正确,提示登录成功,否则,提示登录失败。如果考试成绩大于等于60分,则及格,否则不及…

在甲骨文云容器实例(Container Instances)上部署firefox

甲骨文云推出了容器实例,这是一项无服务器计算服务,可以即时运行容器,而无需管理任何服务器。 今天我们尝试一下通过容器实例部署firefox。 Step1. 创建容器实例 在甲骨文容器实例页面,单击"创建容器实例"&#xff0c…

[漏洞分析] CVE-2022-2602 io_uring UAF内核提权详细解析

本文首发于华为安全应急响应中心公众号: https://mp.weixin.qq.com/s/w_u0FoiFdU0KM397UXJojw 文章目录漏洞简介环境搭建漏洞原理文件引用计数与飞行计数引用计数飞行计数发送过程scm_send接收过程unix_gc垃圾处理机制io_uring原理(仅限漏洞)io_uring_setupio_urin…

零基础学JavaWeb开发(十六)之 mybatis(2)

5、MyBatis - 映射文件标签 5.1、映射文件的顶级元素 select:映射查询语句 insert:映射插入语句 update:映射更新语句 delete:映射删除语句 sql:可以重用的 sql 代码块 resultMap:最复杂&#xff0c…

11. 集合set类型详解

python3 set类型的使用 1. 基础知识 (1) 集合(set)是由一个或数个形态各异的大小整体组成的,构成集合的事物或对象称作元素或是成员。集合是一个无序的不重复元素序列。 (2)基本功能是进行成员…

大年初四,Flutter Forward 中国社区直播活动与你不见不散

之前我们预告过,2023 年 1 月 25 日 (年初四),Flutter 团队将在肯尼亚首都内罗毕举办 Flutter Forward 大会,并同时开启线上直播。本次活动将为展示最新的 Flutter 技术更新,包括一个主题演讲,以及多个技术演讲和线上问…

【兔年之兔子走迷宫】 用一个小游戏对回溯法进行实现 | C++

第六章 回溯法 目录 第六章 回溯法 ●前言 ●一、回溯法是什么? 1.简要介绍 ●二、回溯法经典案例——兔子走迷宫游戏 1.具体情况 2.代码展示(C) 3.结果展示 ●总结 前言 简单的来说,算法就是用计算机程序代码来实…

性能监控和工具使用

1、jvm 内存模型 程序计数器 Program Counter Register:  记录的是正在执行的虚拟机字节码指令的地址,  此内存区域是唯一一个在JAVA虚拟机规范中没有规定任何OutOfMemoryError的区 域  虚拟机:VM Stack  描述的是 JAVA 方法执行的内…

Delphi 中.dproj 文件解析(二、详细解析)

上一篇 介绍了Delphi 的各个版本,本文开始分析.dproj文件。.dproj是一个XML文件,里边包含了我们在Delphi开发环境中对项目设置的所有参数(位于IDE:Project -> Options 中),包括并不限于:版本…

LabVIEW查找范例VI

LabVIEW查找范例VILabVIEW拥有数百个范例VI,用户可搜索需要的范例VI并将其整合到自己创建的VI中。除LabVIEW内置的范例VI之外,在ni.com技术支持页中可查看更多的范例VI。用户可根据应用程序的需要对范例进行修改,也可复制并粘贴一个或多个范例…

LC-1824. 最少侧跳次(动态规划)

1824. 最少侧跳次数 难度中等49 给你一个长度为 n 的 3 跑道道路 ,它总共包含 n 1 个 点 ,编号为 0 到 n 。一只青蛙从 0 号点第二条跑道 出发 ,它想要跳到点 n 处。然而道路上可能有一些障碍。 给你一个长度为 n 1 的数组 obstacles &a…

【FPGA】Verilog 实践:狄摩根定律 | 布尔方程 | 1bit 比较器

写在前面:为了解狄摩根定理和布尔函数的行为,我们使用 Verilog 实现狄摩根定律和布尔函数的行为。生成输入信号后,验证通过仿真实现的结果。 Ⅰ. 前置知识 0x00 离散结构:否定量词的狄摩根定律 否定量词的狄摩根定律是&#xf…

基于自适应降噪的深度神经网络对抗图像检测【论文阅读】

近年来,许多研究表明,深度神经网络(DNN)分类器可能会被对抗性示例所欺骗,这种对抗性示例是通过对原始样本引入一些扰动来设计的。据此,提出了一些强大的防御技术。然而,现有的防御技术往往需要修改目标模型或依赖于攻击…

针对容器场景的多功能渗透工具

介绍 CDK是一款为容器环境定制的渗透测试工具,在已攻陷的容器内部提供零依赖的常用命令及PoC/EXP。集成Docker/K8s场景特有的 逃逸、横向移动、持久化利用方式,插件化管理。 下载/植入 将可执行文件投递到已攻入的容器内部开始使用 https://github.c…

浏览器打不开某些网站是什么原因导致,试试用这些方法来解决

不少小伙伴使用一些浏览器浏览网页的时候,发现打不开某些网站,这是什么原因导致的呢?本文讲汇总几个常见的原因,我们可以通过以下几个原因排查,并且使用下文的解决方法可以试试能否打开网站。打不开网站的原因1、浏览器限制如果用…

SpringMVC工作流程

SpringMVC工作流程 1. SpingMVC的常用组件 1)DispatcherServlet 是一种前端控制器,由框架提供。作用:统一处理请求和响应。除此之外还是整个流程控制的中心,由 DispatcherServlet 来调用其他组件,处理用户的请求 2&am…

在甲骨文云容器实例(Container Instances)上部署Oracle Linux 8 Desktop

甲骨文云推出了容器实例,这是一项无服务器计算服务,可以即时运行容器,而无需管理任何服务器。 今天我们尝试一下通过容器实例部署Oracle Linux 8 Desktop。 创建容器实例 在甲骨文容器实例页面,单击"创建容器实例"&am…

【甄选靶场】Vulnhub百个项目渗透——项目五十六:sp-jerome(squid代理,计划任务)

Vulnhub百个项目渗透 Vulnhub百个项目渗透——项目五十六:sp-jerome(文件上传,缓冲区溢出) 🔥系列专栏:Vulnhub百个项目渗透 🎉欢迎关注🔎点赞👍收藏⭐️留言&#x1f4…

微信公众号主体已注销 如何办理账号迁移和公证书?

公众号主体公司已经注销,公众号也可以办理迁移的。而且需要尽快迁移,如果被微信系统检测到主体注销,而公众号还在经营就会要求限期迁移,否则公众号将被冻结。 下面我们就来说一下,主体已注销如何办理公众号迁移。 注&a…