Java多态

多态

多态相对于封装和继承这两个名词就不是那么生活化了。这个词最早是一个生物的专业用词,它的指的是同一个物种在不同的环境当中可能出现的多样化表现。那么衍生到了面向对象编程中,它的含义呢,我们用一句经典来话来描述:相同的行为,不同的实现。

1、多态指的是行为的多样性,没有属性多态这一说;

2、相同的行为指的是同名方法,也就是说方法名相同,我们就认为这是相同的行为。 由此,我们前面学习的方法重载和方法重写其实都是多态的表现。

最近面试看到的:属性能不能重写? 1、首先这个说法不专业,重写特指的是方法,但是它要描述的意思其实我们懂,那就是父类中定义了一个属性,子类能不能再定义一个同名属性把它给覆盖掉;

2、在语法上,这是可以的,不会报错。但是子类定义的属性是不会把父类定义的属性给覆盖掉;而是两个属性同时存在于对象身上,父类定义的存在于子类对象的父类对象部分(上半截),子类定义的存在于子类对象的子类特有部分(下半截)。那么,如何区分呢?用this.访问子类定义的该属性;用super.访问父类定义的该属性。

3、在实际场景中,这种设计是没有意义的。因为父类定义了一个属性,子类通过继承自动拥有了这个属性,那么子类再去定义一个一摸一样的属性是没有任何意义的,属于重复劳动。这是属于子类的设计人员没有理解父类设计的意图。

多态的意义

封装是面向对象的基础; 继承是在封装的基础上,实现代码的复用性; 多态考量的是代码的丰富度。

多态分为两种: 1、静态多态;2、动态多态。

这里的静态和我们前面学习的static关键字没有关系,它描述的是:在编译期既能确定某个多态方法的具体执行效果; 这里的动态多态是指在运行期,根据绑定对象的不同,才能确定多态方法执行的效果。

我们在前面学过的方法的重载和方法的重写都是属于静态多态。静态多态虽然有丰富度的体现,但是是不够的,因为它在编译期就把执行效果固定下来了。而我们以后用得更多的是动态多态。

动态多态是由两个技术合并使用才有的效果:动态绑定技术 + 方法的重写。

动态绑定技术

首先我们从现象上来看一个效果: 本类引用 指向 本类对象; 父类引用 指向 子类对象;

在Java当中只有这两种情况,也就是说赋值符号左右两端如果类型不一致,那么只有后面这种情况。

从内存上解释

为什么父类引用可以指向子类对象呢? 既然是父子关系,还是在做继承,那么还是跟内存叠加有关系。每一个子类对象的上半截都是一个完整的父类对象部分,当父类引用指过去的时候,是能够看到完整的父类对象信息的。

没有继承关系的类,不能保证A类引用指到B类对象,能看到B类对象中有A类定义的内容,所以不允许!

子类引用指向父类对象的时候,父类对象里面没有子类特有部分,所以缺失了内容,也不允许!

从场景上解释

一个对象属于子类,一定也属于它的父类。子和父是is-a关系,这是说得通的。

但是一个对象属于父类,你能保证它一定属于子类吗?

而没有继承关系的,那就更说不通的了,比如:指鹿为马。 明明是一个鹿的对象,你偏要用马的引用去指向它,肯定是不对的。你可以说它是动物、可以说它是宠物、因为鹿is-a动物;鹿 is-a 宠物;都是可行的,但鹿 is not a 马。

动态体现在哪儿?

如果我们手上现在拥有一个父类引用,那么我们就不能确定这个引用到底是指向哪一个具体的对象的了。

它既可能指向自己类型的对象,也可能指向自己的各种子类对象。而自己的某个方法,是可以被子类重写成不同的实现效果的。那么用这个引用执行重写方法,也就不能确定到底重写前还是重写后,是A子类重写后,还是其它子类重写后的效果了。只有等程序运行起来以后,根据该引用具体绑定的对象到底是谁,才能够运行出具体的效果。--- 这就是动态的体现。

语法细节

转型技术

赋值符号左右两端数据类型不一致,就会发生数据类型转换。 父类引用 = 子类对象 也是两端数据类型不一致,所以也属于转型技术。

我们用我们前面学习的基本数据类型转型技术去推衍现在的引用数据类型的转型技术。

基本数据类型转型技术

1、前提:不是所有基本数据类型之间都能够进行转型,boolean不参与的;

2、自动类型转换 小类型值 赋值给 大类型的变量 强调: 这里的大小 是 数据类型能表示的范围的大小,而不是空间的大小。

int num = 'A'; float f = num; double d = 100;

效果:不需要使用任何特殊语法,直接完成类型转换并且赋值成功。

3、强制类型转换 大类型的值 赋值给 小类型的变量

效果: 3-1、直接书写后,编译报错; 3-2、使用(目标类型)的强转语法,编译才能够通过; 3-3、运行的效果是有风险性的,精度有可能丢失。

引用数据类型转型技术

1、前提:不是所有引用数据类型之间都能够做转型,只有有继承关系的类型之间才可以;

2、自动类型转换 子类对象 赋值给 父类引用 子类表示的范围 是小于 父类表示的范围,所以仍然是把小的数据值交给大的变量。与基本数据类型的自动转换要求是一摸一样的。

只是说它有另一个特殊的名字,又叫做“向上转型”而已。因为在继承树上,父类在上,子类在下;

效果:不需要使用任何特殊语法,直接完成类型转换并且赋值成功。

3、强制类型转换 大类型的值 赋值给 小类型的引用

又被称为"向下转型".

效果: 1、直接书写后,编译报错; 2、使用(目标类型)的强转语法,编译才能够通过; 3、运行的效果是有风险性的,风险性是运行时报错(ClassCastException),中断程序的执行。

对风险性探讨: 1、我们发现并不是每次强转都一定成功,那么情况时如何的呢? 要想强转以后,编译通过且运行也通过,只有一种情况,那就是:最终的内存结果只能是本类引用指向本类对象。

2、强转语法只是在编译期进行一个强制性的语法说明,说明什么呢?告诉编译器,我这个父类引用确实是指向的某种子类对象。

3、但是运行起来以后,如果满足你的强制说明,那么没有问题运行成功;如果不满足你的强制说明,那么就会运行失败,报出ClassCastException。

强调:强转语法不是把A类对象变成B对象,只是在编译期达成的一个口头约束而已。

父类引用指向子类对象,我们能访问什么呢?

1、父类引用只能看到子类对象从父类继承而来的属性和行为,当然要受访问修饰符限制; 注意:子类对象身上是有子类特有属性和行为的,只是站在父类引用的角度上看不到而已。

2、要想看到,要把引用换成子类引用,这个时候要使用强转语法,同时还必须保证运行起来以后真正给出的对象是符合强转语法的。

3、特例是在父类中定义,被子类重写的行为。由于这个行为是定义在父类中,所以父类引用能看到;而对象又是子类对象,所以执行的效果是子类重写后的效果。

练习:书写一个宠物类Pet,拥有一个叫的行为;书写Pet的两个子类Dog和Cat,分别实现叫的行为。再书写一个主人类Master,拥有一个宠物对象,主人有一个行为是喂养feed,在该方法中调用自己宠物叫的行为。最后,在main方法中测试。

instanceof

在练习当中,我们看到在有的场景里面,确实会存在需要强转的情况。但是,强转又有风险度,所以,我们需要先判断类型是否匹配,这就要用到instanceof了。

instanceof是一个关键字,也是一个运算符。它是专门用来判断一个对象是否属于某个类型的,运算后的结果是boolean型结果。

语法: 对象 instanceof 类型

instanceof是专门用来规避强转带来的ClassCastException风险的,类似于非空判断专门用来解决NullPointerException风险的。

多态的应用

多态参数

当我们在设计参数的时候,把参数的类型设计为父类类型,那么所有的子类对象都能够通过这个参数,传递到这个方法里面去。

​
public void cure(角色 r){
​
    if(r instanceof 士兵){
    
    }else if(.....){
    
    }
​
}
​

这样的多态应用带来了面向对象设计中非常重要的一个原则:开闭原则。

开闭原则:Software should be opened for extension, but closed for modification。

软件对于扩展来说应该是开放的,对于修改来说应该是关闭。

也就是说好的软件设计,应该能够可以随着业务的扩展去增加新的功能,但是不应该修改已有的功能。

多态集合

int[] array = new int[10];

Object[] arrayObj = new Object[10];

可以解决数组只能存放同一数据类型元素的问题。

补一下

switch的新语法

var关键字

Java语言和JavaScript语言有一个很重要的区别: Java语言是强类型的编程语言;而JS是弱类型的。

int num = 10;
String msg = "hello";
var num = 10;
var name = "zhang3";
var pi = 3.14;
​
num = "hello";
​

在15年左右的时候,Java想去学习JS的这种声明变量的简便性,所以它也引入了var关键字来声明变量。

但问题是,Java本身是强类型的,引入了以后又不能改变它的强类型本质,所以导致这个关键字不伦不类有很多限制。

1、必须要对var声明的变量马上赋值,因为编译器是根据这个赋的值的类型才能判定这个变量是什么数据类型的;

2、一旦赋值成功后,这个变量的类型就被确定了,后面也不能更改,也不能存放其它类型的数据值;

3、var声明的变量只能是局部变量,不能声明为属性的类型,也不能声明为参数的类型。

4、所以在java中这个var变量的使用就没有啥意义了。 唯一的意义可能仅仅在于如果一个局部变量的类型名很长的时候,可以帮助我们少写点代码。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
简介 Symphony([ˈsɪmfəni],n.交响乐)是一个现代化的社区平台,因为它: 实现了面向内容讨论的论坛 包含了面向用户分享、交友、游戏的社交网络 集成了聚合独立博客的能力,共建共享优质资源 并且 100% 开源 欢迎到 Sym 官方讨论区了解更多。另外,如果你需要搭建一个企业内网论坛,请使用 SymX。 动机 Sym 的诞生是有如下几点原因: (正版) 很多系统界面上仍然保持着老式风格,远远没有跟上时代发展的脚步,它们没有创新、好玩的特性,缺少现代化的交互元素和用户体验 大部分系统是从程序员的角度进行设计的,没有考虑实际的产品、运营需求,这类系统功能过于简陋、细节不够精致、缺乏长期维护 另外,我们正在探索新的社区模式,实现独奏(Solo)与协奏(Symphony)相结合的社区新体验 (野版) 万能的 GitHub 上连个能用的 Java 社区系统都找不到,Sym 填补了这个宇宙级空白 做最 NB 的开源社区系统,预计几年以后 82% 的社区都将是 Sym 搭建的 作者技痒,炫技之作,Ruby/Python/Node.js/(特别是)PHP 怎么能比得过 Java 案例 个人维护: 黑客派 宽客网 贵州IT 超级产品经理 Titandb 学习主站 呆萌狮 - Demo's 公司维护: 四方环视 如果你也搭建好了,欢迎通过 Pull Request 将你的站点加到这个列表中 :-p 功能特性 具体功能点细节可浏览 Sym 功能点脑图,下面列出了 Sym 的主要特性,说明 现代化 的由来。 好用的编辑器 Markdown:支持 GFM 语法以及一些扩展语法 格式调整:粗体、斜体、超链接、引用、列表等可以通过工具栏按钮,同时也支持快捷键 文件上传:支持复制粘贴或者拖拽上传图片;支持上传普通文件;对 MP3 会使用在线播放器进行渲染 剪贴板处理:自动将复制的内容转换为 Markdown 格式;外链的图片自动上传站内 @用户:根据用户名自动补全,支持快捷键 Emoji:支持大部分主流 Emoji 表情,快捷键自动补全 数学公式:支持 LaTex 数学公式渲染 数据暂存:支持本地浏览器暂存数据,避免意外情况导致编辑内容丢失 智能、灵活的信息架构 传统的节点式社区要求帖子必须 分类 到某一个节点下,信息架构方式属于自上而下。Sym 不是自上而下的节点式信息架构,帖子不需要固定分类,通过标签 聚合 到某个领域下。 标签:根据帖子内容智能抽取关键字进行标签自动补全,一篇帖子关联多个标签。标签和标签之间以带边权重的图结构进行描述,方便进行相关计算 领域:一个领域下包含了多个标签,通过标签将帖子自动聚合到具体领域,随时可以通过增减关联标签从而达到调整领域范围,最终聚合出适合的帖子列表 满足多样化的发帖需求 目前支持 4 中帖子类型,满足不同用户的偏好: 普通帖子:提问或分享对别人有帮助的经验与见解 思绪:写作过程的记录与重放,文字版的沙画表演 (?) 小黑屋:邀请好友在私密空间中进行交流 同城广播:发起你所在城市的招聘、Meetup 等 另外,所有帖子都可以设置 打赏区 ,打赏区可以放置一些“珍藏”内容,只有打赏后的用户才能浏览。打赏区编辑器同样支持 Markdown、Emoji 和文件上传等特性。打赏区支持内容更新,并可以随时调整打赏积分值。 对于测试帖,可以使用 Sandbox 机制:带有 Sandbox 标签的帖子将视为测试帖,不会显示在首页或是某领域内,只会展现在发帖者自己的帖子列表中。 人性化的回帖交互 实时呈现:回帖提交后其他浏览者可以不刷新页面就实时看到你的回帖 随时滚动:浮出式回帖编辑器方便回帖者随时滚动屏幕查看其他内容,不必担心焦点丢失 真正的回复:回复是针对回帖而言的,而 @ 是针对用户而言的,@ 是提及不是回复,很多系统都没有考虑到这一点。回复/引用可以在当前位置进行展开浏览,也可以跳转到回帖处,并支持跨分页跳转 智能机器人:回帖时可以让机器人也参与到讨论中来,活跃气氛的同时说不定机器人真的能解决一些问题呢 用户个性化设置 用户可以自己设置很多参数以满足个性化需求: 帖子列表浏览分页每页条目数 回帖浏览模式:传统(按发布时间升序,无实时推送刷新);实时(按发布时间降序,实时推送新回帖) 头像浏览模式:原图(支持 gif 动图);静态图 Chrome 通知/邮件订阅/键盘快捷键开关 设置常用 Emoji,方便发布内容时快速插入表情 除了功能个性化配置项,还有很多隐私项开关: 是否公开帖子/回帖列表 是否公开

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值