接口多态与方法多态
作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
在上一篇设计山寨版Stream API时,有一个技巧被频繁使用:接口多态。
接口,用的是函数式接口,即接口内部有且仅有一个抽象方法。
多态,原本指的是接口下有多个子类实例可以指向接口引用,但由于函数式接口恰好仅有一个方法,此时接口多态等同于“方法多态”,即一个抽象方法拥有多个不同的具体实现。
接口多态
我们都知道Java是面向对象的语言,它具备多态性。私以为,多态的精髓在于晚绑定。什么意思呢?
PocketMon pocketMon = new Pikaqiu();
pocketMon.releaseSkill();
只看pocketMon.releaseSkill()你能猜出来技能是电击还是喷火吗?
哦?一眼就看出来了?
这样呢?
Properties pro = new Properties();
FileInputStream in = new FileInputStream("pocketmon.properties");
pro.load(in);
PocketMon pocketMon = Class.forName(pro.getProperty("nextPocketMon")).newInstance();
pocketMon.releaseSkill();
完全看不出来了。
即使你打开pocketmon.properties看了是皮卡丘,运行时虚拟机看到的可能是我修改后的喷火龙。
这种现象其实很奇妙:明明代码都写死了,但虚拟机却无法提前确定具体会是哪只神奇宝贝在调用releaseSkill(),除非实际运行到这行代码。而这,正是得益于多态。
多态的原理,本质是还是JVM层面通过运行时查找方法表实现的。可以简单理解为,JVM在运行时需要去循环遍历这个方法对应的多态实现,选择与当前运行时对象匹配的方法进行调用。所以,从理论上来说,晚绑定的多态在性能上是不如早绑定的(直接写死,不用多态)。而多态是设计模式的灵魂,所以对于一些非常、非常、非常要求性能的场景来说,过于繁重的设计反而会降低性能。说白了,这世上就不存在多、快、好、省。
多态是“晚绑定”思想的体现:对于Java而言,方法的调用并不是编译时绑定,而是运行时动态绑定的,取决于引用具体指向的实例。
方法多态
我生造了“方法多态”这个概念,但这个概念在函数式接口的前提下是站得住脚的,而且有利于跳出面向对象,贴近函数式编程。
我们来看一个需求:
要求写一个cook()方法,传入鸡翅和可乐,你给我做出可乐鸡翅。
很多人可能下意识地就把代码写死了:
public static CokaChickenWing cook(Chicken chicken, Coka coka){1.放油、放姜;2.放鸡翅;3.倒可乐;4.return CokaChickenWing;
}
但是,网上也有人说应该先倒可乐再放鸡翅,每个人的口味不同,做法也不同。有没有办法把这两步延迟确定呢?让调用者自己来安排到底是先倒可乐还是先放鸡翅。
可以这样:
public static CokaChickenWing cook(Chicken chicken, Coka coka, function twoStep){1.放油、放姜;2~3.twoStep();4.return CokaChickenWing;
}
想法很好:既然这两步不确定,那么就由调用者来决定吧,让调用者自己传进来。
我们知道Java是不能直接传递方法的,但利用策略模式可以解决这个问题。
定义一个接口:
interface TwoStep {void excute();
}
然后呢?
public static CokaChickenWing cook(Chicken chicken, Coka coka, TwoStep twoStep){1.放油、放姜;2~3.twoStep.excute();4.return CokaChickenWing;
}
这里twoStep.excute()是确定的吗?
没有。
你说它是先倒可乐,再放鸡翅?我偏要说它是先放鸡翅,再倒可乐!反正接口也没方法体,具体实现要看你传进来什么对象。
所以twoStep.excute()充其量只是先替“某些操作占个坑”,后面再确定。
什么时候确定呢?
main(){TwoStep twoStep = new TwoStep(){@Overridepublic void excute(){2.先放鸡翅3.再倒可乐}}// 调用cook时确定(运行时)cook(chicken, coka, twoStep);
}public static CokaChickenWing cook(Chicken chicken, Coka coka, TwoStep twoStep){1.放油、放姜;2~3.twoStep.excute();4.return CokaChickenWing;
}
来,学过Lambda表达式后,我们换个时髦的写法:
main(){// 调用cook时确定 方案1cook(chicken, coka, (鸡翅, 可乐) -> 2.先放鸡翅,3.再倒可乐);// 调用cook时确定 方案2cook(chicken, coka, (鸡翅, 可乐) -> 2.先倒可乐,3.再放鸡翅);
}public static CokaChickenWing cook(Chicken chicken, Coka coka, TwoStep twoStep){1.放油、放姜;2~3.twoStep.excute();4.return CokaChickenWing;
}
这就是我所谓的“方法多态”:通过函数式接口把形参的坑占住,后续传入不同的Lambda实现各自逻辑。
晚绑定与模板方法模式
在设计模式中策略模式和模板方法看起来有点像,但其实不一样。策略模式使用接口占坑,然后传入实际对象调用需要的方法,而模板方法模式是用抽象方法占坑,粒度其实小一些。
晚绑定最典型的应用就是模板方法模式:抽象类确定基本的算法骨架,把不确定的、变化的部分做成抽象方法剥离出去,由子类来实现。
还是以发送验证码为例:
/*** 验证码发送器** @author mx*/
public abstract class AbstractValidateCodeSender {/*** 生成并发送验证码*/public void sendValidateCode() {// 1.生成验证码String code = generateValidateCode();// 2.把验证码存入Session// ....// 3.抽象方法占坑,用于发送验证码sendCode();}/*** 具体发送逻辑,留给子类实现:发送邮件、或发送短信都行*/protected abstract void sendCode();/*** 生成验证码** @return*/public String generateValidateCode() {return "123456";}}
对于上面的模板,我们可以有多种实现方式,以便把sendCode()这个坑填上:
/*** 短信验证码发送** @author mx*/
public class SmsValidateCodeSender extends AbstractValidateCodeSender {@Overrideprotected void sendCode() {// 通过阿里云短信发送}
}
/*** QQ邮箱验证码发送** @author mx*/
public class EmailValidateCodeSender extends AbstractValidateCodeSender {@Overrideprotected void sendCode() {// 通过QQ邮箱发送}
}
作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
进群,大家一起学习,一起进步,一起对抗互联网寒冬
相关文章:
接口多态与方法多态
作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 在上一篇设计山寨版Str…...
js小技巧|如何提取经过Function函数混淆了的代码
关注它,不迷路。 本文章中所有内容仅供学习交流,不可用于任何商业用途和非法用途,否则后果自负,如有侵权,请联系作者立即删除! 1.需求 星友发过来一个混淆代码,打开一看,长这…...
【GitLab】流水线入门
(꒪ꇴ꒪ ),Hello我是祐言QAQ我的博客主页:C/C语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍快上🚘,一起学习,让我们成为一个强大的攻城狮࿰…...
es 中文前缀短语匹配(搜索智能补全)
需求:es进行前缀匹配,用来进行智能补全 过程:es正常的prefix只能进行词语匹配,而中文的分词大部分按字分词,不按语义分词,所以无法搜索出正确的前缀匹配,而能进行短语匹配的match_phrase_prefix…...
机器学习之决策树及随机森林
决策树 概念 决策树(Decision Tree)是一种常见的机器学习算法,用于分类和回归任务。它是一种树状结构,其中每个内部节点表示一个特征或属性,每个分支代表一个决策规则,而每个叶节点表示一个输出标签或值。 构建决策树过程 构建决策树的过程通常涉及以下步骤: 数据准…...
用通俗的方式讲解Transformer:从Word2Vec、Seq2Seq逐步理解到GPT、BERT
直到今天早上,刷到CSDN一篇讲BERT的文章,号称一文读懂,我读下来之后,假定我是初学者,读不懂。 关于BERT的笔记,其实一两年前就想写了,迟迟没动笔的原因是国内外已经有很多不错的资料࿰…...
数据结构-01-数组
每一种编程语言中,基本都会有数组这种数据类型。不过,它不仅仅是一种编程语言中的数据类型,还是一种最基础的数据结构。 1-数组的概念和特性 数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来…...
甘草书店记: 2023年10月11日 星期三 晴 「做有光的人,照亮他人,也引人同行」
发了两篇《甘草书店记》,书店计划公之于众,收获了不少人的赞扬和鼓励,来自生活中的友人,来自麦田的客户和朋友,来自图书界的同行前辈,也来自商界的同仁。其中,最特别留言来自甘草书店投资方的张…...
让 OpenAI GPT4 出 10 道题测试其他开源大语言模型
让 OpenAI GPT4 出 10 道题测试其他开源大语言模型 1. 中文题目及答案2. 日文题目及答案3. 英文题目及答案 1. 中文题目及答案 数学题:一个矩形的长是10厘米,宽是5厘米,求它的面积。 答案:面积 长 x 宽 10厘米 x 5厘米 50平方厘…...
动态库与静态库
1. 库 是代码的二进制的封装形式 在其他的源代码或库中,可以直接调用库的,但是又看不到它 没有公开源代码 库的这种实现方法有利于模块化 而且只要接口合理 不影响库的使用的 sum.c sum.h int sum(int a,int b) { return ab; } xxx.c 需要使用…...
pdf文件编辑,[增删改查]
pdf文件是投标文件中必不可少的格式,传统的方式先编辑word格式,最后生成pdf,但是有时候需要直接编辑pdf文件,编辑pdf的工具无疑 “adobe acrobat dc”是最好用的之一了 1.把图片文件添加到pdf指定位置,例如把一张图片添…...
如何与LEONI建立EDI连接?
莱尼LEONI是一家为汽车及其他行业提供能源数据管理产品、解决方案及服务的全球供应商。供应链范围从研发生产标准化电缆、特种电缆和数据电缆到高度复杂的布线系统和相关组件。本文将介绍如何与莱尼LEONI建立EDI连接。 什么是EDI? EDI全称Electronic Data Interch…...
算法中的时间复杂度,空间复杂度
一、前言 算法(Algorithm)是指用来操作数据、解决程序问题的一组方法。对于同一个问题,使用不同的算法,也许最终得到的结果是一样的,但在过程中消耗的资源和时间却会有很大的区别 衡量不同算法之间的优劣主要是通过时…...
Python基础:推导式(Comprehensions)详解
1. 推导式概念 Python推导式(comprehensions)是一种简洁而强大的语法,用于从已存在的数据(列表、元组、集合、字典等)中创建新的数据结构。推导式包括: 列表推导式元组推导式字典推导式集合推导式 2. 列表…...
安防监控视频融合平台EasyCVR定制化页面开发
安防监控EasyCVR视频汇聚平台基于云边端智能协同,支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。安防视频平台EasyCVR拓展性强,视频能力丰富,具体可实现视频监控直播、视频轮播、视频录像、云存储、回放与检索…...
Roll-A-Ball 游戏
Roll-A-Ball 游戏 1)学习资料 b站视频教程:https://www.bilibili.com/video/BV18W411671S/文档: * Roll-A-Ball 教程(一), * Roll-A-Ball 教程(二)线上体验roll-a-ball成品 * http://www-personal.umich.e…...
医疗影像数据集—CT、X光、骨折、阿尔茨海默病MRI、肺部、肿瘤疾病等图像数据集
最近收集了一大波关于CT、X光等医疗方面的数据集包含骨折、阿尔茨海默病MRI、肺部疾病等类型的医疗影像数据,废话不多说,给大家逐一介绍!! 1、彩色预处理阿尔茨海默病MRI(磁共振成像)图像数据集 彩色预处理阿尔茨海默病MRI(磁共…...
Linux僵死进程及文件操作
1.僵死进程(僵尸进程): 1.僵死进程产生的原因或者条件: 什么是僵死进程? 当子进程先于父进程结束,父进程没有获取子进程的退出码,此时子进程变成僵死进程. 简而言之,就是子进程先结束,并且父进程没有获取它的退出码; 那么僵死进程产生的原因或者条件就是:子进…...
用Python写一个浏览器集群框架
更多Python学习内容:ipengtao.com 在分布式爬虫和大规模数据采集的场景中,使用浏览器集群是一种有效的方式,可以提高数据采集的速度和效率。本文将介绍如何用Python编写一个简单但强大的浏览器集群框架,以应对需要使用多个浏览器实…...
【Github】git安装
我们经常需要对github上的项目进行复现或者使用,git指令可以方便我们更好地实现他们。 Part 0. 准备 配置代理IP 面对问题:关于登陆github网站网速慢、下载git项目网速慢。 解决:无论是windows还是linux系统,都可以找到/etc/ho…...
用数字逻辑门复刻柏林钟:从二进制编码到硬件实现
1. 项目概述:用数字电路复刻“柏林钟”作为一个在柏林长大的孩子,我从小就对库达姆大街上的那座“柏林钟”着迷。它不像传统时钟那样用指针或数字告诉你时间,而是通过几排不同颜色的发光方块,以一种近乎艺术的方式呈现时间。这种独…...
嘈杂工业场景下的自适应VAD与双码本声纹识别鉴权系统:基于端侧轻量化神经网络与向量量化(VQ)重构
在大型化工车间、能源集控中心以及金融极密隔离库房中,离线声纹识别是物理访问控制和身份安全核验的重要生物特征屏障。然而,在环境本底噪声高达80dB以上的恶劣工业场景下,常规的语音活动检测(VAD)会频繁误触ÿ…...
Linux服务器被挖矿木马劫持的五步应急处置指南
1. 这不是“中病毒”,是服务器被劫持成了矿机——先别慌,但必须立刻断网“服务器被黑客攻击,用来挖矿!”——这句话在运维圈里一出,比收到OOM告警还让人头皮发紧。它不像网页被挂马、数据库被拖库那样有明显业务影响&a…...
如何让Rhino 3D模型在Blender中保持完整数据:import_3dm插件深度解析
如何让Rhino 3D模型在Blender中保持完整数据:import_3dm插件深度解析 【免费下载链接】import_3dm Blender importer script for Rhinoceros 3D files 项目地址: https://gitcode.com/gh_mirrors/im/import_3dm 当建筑师需要在Blender中渲染Rhino设计的建筑模…...
保姆级教程:在Windows 10上用QEMU+Kylin搭建可内外网访问的完整开发环境
在Windows 10上构建QEMUKylin全功能开发环境的终极指南当开发者需要在本地快速搭建一个隔离的国产操作系统开发环境时,QEMU虚拟化方案配合银河麒麟系统能提供高度灵活的沙箱体验。本文将手把手带你完成从零配置到内外网联通的完整工作流,涵盖虚拟化环境部…...
LoRa物联网与动态基线算法在养殖体温监测中的实战应用
1. 项目概述:为什么我们需要一个智能体温监测系统?在规模化养殖场里干了十几年,我见过太多因为体温异常没被及时发现而导致的损失。一头育肥猪突然不吃食,等饲养员第二天巡栏发现时,可能已经高烧好几天,继发…...
从零构建FOC轮腿机器人:开源平衡机器人完整指南
从零构建FOC轮腿机器人:开源平衡机器人完整指南 【免费下载链接】foc-wheel-legged-robot Open source materials for a novel structured legged robot, including mechanical design, electronic design, algorithm simulation, and software development. | 一个…...
基于TESS光变曲线与深度学习的O型星物理参数预测研究
1. 项目概述与核心挑战在恒星天体物理研究中,大质量O型星扮演着至关重要的角色。它们不仅是宇宙中光度最高的天体之一,其强烈的辐射、恒星风和最终的超新星爆发,更是驱动星系化学演化和能量注入星际介质的关键引擎。然而,深入理解…...
NHSE终极教程:5分钟掌握动物森友会存档编辑技巧
NHSE终极教程:5分钟掌握动物森友会存档编辑技巧 【免费下载链接】NHSE Animal Crossing: New Horizons save editor 项目地址: https://gitcode.com/gh_mirrors/nh/NHSE 还在为《集合啦!动物森友会》的收集烦恼吗?想快速打造梦想岛屿却…...
收藏|2026年大模型算法岗崛起!程序员小白入门高薪赛道全攻略
前些年,算法岗位一直稳居技术圈高薪行列,无数程序员争相入局,也成为计算机专业毕业生求职首选方向。 伴随大模型技术飞速迭代落地,行业就业格局迎来重大变革。如今含金量最高、人才缺口最大、长期发展潜力顶尖的岗位,已…...
