Java高手速成 | 多态性实战

news2024/11/16 18:03:46

 多态性(polymorphism)是OOP最强大、最有用的特性。截至目前,多态性用到了所讲的所有其他OOP概念和特性。在通向精通Java语言编程的征程上,多态性是最高级别概念站点。

一个对象具有跟另一不同类的对象一样的行为,或者具有跟另一不同接口的实现一样的行为。具有这样行为的能力被称为多态性(polymorphism)。如果在因特网上搜索“多态性”一词,就会发现它是“以多种不同形式出现的情况”。变态(metamorphosis)是“通过自然或超自然的手段,改变某物或某人的形状或性质,使其变成完全不同的形状或性质。”因此,Java多态性是对象在不同的条件下表现或展示出完全不同行为的能力,如同经过了一个变态的过程。

下面开始动手实战,直观理解这一概念。这里采用的是对象工厂(object factory)——一种工厂式的特定编程实现手段。对象工厂是“一种方法,返回的是发生了改变了的原型(或类)的对象”。

01、对象工厂

对象工厂背后的理念是创建一个方法,该方法在某些条件下返回某个类型的新对象。举例来说吧。拿CalcUsingAlg1和CalcUsingAlg2这两个类做示范:

interface CalcSomething{
double calculate();
}
class CalcUsingAlg1 implements CalcSomething{
public double calculate(){ return 42.1; }
}
class CalcUsingAlg2 implements CalcSomething{
private int prop1;
private double prop2;
public CalcUsingAlg2(int prop1, double prop2) {
this.prop1 = prop1;
this.prop2 = prop2;
}
public double calculate(){ return prop1 * prop2; }
}

 

可以看到,这两个类实现相同的接口CalcSomething,但使用的算法不同。

现在,假设这样决定:选择所用的算法是在一个属性文件中,那么,就可创建以下对象工厂:

class CalcFactory{
public static CalcSomething getCalculator(){
String alg = getAlgValueFromPropertyFile();
switch(alg){
case "1":
return new CalcUsingAlg1();
case "2":
int p1 = getAlg2Prop1FromPropertyFile();
double p2 = getAlg2Prop2FromPropertyFile();
return new CalcUsingAlg2(p1, p2);
default:
System.out.println("Unknown value " + alg);
return new CalcUsingAlg1();
}
}
}

这个工厂根据getAlgValueFromPropertyFile()方法返回的值,选择要使用哪种算法。

对第二个算法而言,还用到getAlg2Prop1FromPropertyFile()和getAlg2Prop2FromPropertyFile()方法来获取算法的输入参数。

但这种复杂性对客户是隐藏的。示范如下:

CalcSomething calc = CalcFactory.getCalculator();
double result = calc.calculate();

可以添加新的算法变量,更改算法参数的源代码或算法选择的过程,但客户端不需要更改代码。多态性的威力体现于此。此外,可以使用继承来实现多态行为。思考下面的类:

class CalcSomething{
public double calculate(){ return 42.1; }
}
class CalcUsingAlg2 extends CalcSomething{
private int prop1;
private double prop2;
public CalcUsingAlg2(int prop1, double prop2) {
this.prop1 = prop1;
this.prop2 = prop2;
}
public double calculate(){ return prop1 * prop2; }
}

 那么,这里的工厂会呈现下面的模样:

class CalcFactory{
public static CalcSomething getCalculator(){
String alg = getAlgValueFromPropertyFile();
switch(alg){
case "1":
return new CalcSomething();
case "2":
int p1 = getAlg2Prop1FromPropertyFile();
double p2 = getAlg2Prop2FromPropertyFile();
return new CalcUsingAlg2(p1, p2);
default:
System.out.println("Unknown value " + alg);
return new CalcSomething();
}
}
}

 但是,客户端代码仍然不变:

CalcSomething calc = CalcFactory.getCalculator();
double result = calc.calculate();

如果可以选择,有经验的程序员将使用公共接口来实现。

公共接口允许更灵活的设计,因为Java的一个类可以实现多个接口,但仅可以扩展(继承)一个类。

02、instanceof运算符

不幸的是,事情并不总是那么简单。有时,程序员不得不处理由不相关的类组装而成的代码,而这些不相关的类甚至来自不同的框架。这种情况下,使用多态性可能不是一个可选的办法。不过,仍然可以隐藏算法选择的复杂性,甚至使用instanceof运算符来模拟多态行为。对象是某个类的实例时,instanceof运算符返回true。

假设有两个不相关的类,具体如下:

class CalcUsingAlg1 {
public double calculate(CalcInput1 input){
return 42. * input.getProp1();
}
}

class CalcUsingAlg2{
public double calculate(CalcInput2 input){
return input.getProp2() * input.getProp1();
}
}

 每个类都期待输入某类型的对象,具体如下:

class CalcInput1{
private int prop1;
public CalcInput1(int prop1) { this.prop1 = prop1; }
public int getProp1() { return prop1; }
}

class CalcInput2{
private int prop1;
private double prop2;
public CalcInput2(int prop1, double prop2) {
this.prop1 = prop1;
this.prop2 = prop2;
}
public int getProp1() { return prop1; }
public double getProp2() { return prop2; }
}

 假设一下,如果实现的方法接收到这样一个对象:

void calculate(Object input) {
double result = Calculator.calculate(input);
//other code follows
}

 

这里,仍然使用了多态性,因为将输入描述为Object类型。能够做到这一点,是因为Object类是所有Java类的基类。现在,看看Calculator类是如何实现的:

class Calculator{
public static double calculate(Object input){
if(input instanceof CalcInput1){
return new CalcUsingAlg1().calculate((CalcInput1)input);
} else if (input instanceof CalcInput2){
return new CalcUsingAlg2().calculate((CalcInput2)input);
} else {
throw new RuntimeException("Unknown input type " +
input.getClass().getCanonicalName());
}
}
}

 

由上可见,Calculator类用的是instanceof运算符来选择适当的算法。

通过使用Object类作为输入类型,Calculator类也利用了多态性,但是其大部分实现与多态性无关。

然而,从外部看,Calculator类似乎是多态的。确实如此,但只是在一定程度上呈多态性。

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

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

相关文章

QT5.14.2使用回顾

前面已有博客介绍了QT的安装和配置VS2019配置Qt5.14.2以及在线配置Qt5.15.2,这里再接着该版本说明下QT的使用,主要是汇总下之前博客中的内容:Ubuntu下的基本知识点(二)QT4.8.6工程到QT5.12.1的迁移注意前面安装时候&am…

小程序开发超好用的UI组件——Vant Weapp

Vant Weapp 是有赞前端团队开源的一套小程序 UI 组件库,助力开发者快速搭建小程序应用。它所使用的是 MIT 开源许可协议,对商业使用比较友好,官网地址:https://vant-contrib.gitee.io/vant-weapp/#/home 安装 Vant 组件库 在小程序项目中&a…

设计模式学习(十):lterator迭代器模式

一、什么是Iterator模式使用Java语言显示数组arr中的元素时&#xff0c;我们可以使用下面这样的for循环语句遍历数组。for (int i 0; i < arr.length; i){system.out.println(arr[i]); }请注意这段代码中的循环变量i。该变量的初始值是o&#xff0c;然后会递增为1,2&#x…

halo 1.4.17 使用Mysql 安装与配置

1 下载代码 https://github.com/halo-dev/halo/archive/refs/tags/v1.4.17.zip 2 查看1.4版本文档 https://docs.halo.run/1.4/ 1.3 使用idea打开并设置jdk 11 1.4 将h2配置成为mysql 修改前 修改后 1.5 打包成jar halo使用的是Gradle&#xff0c;打包时&#xff0c…

微软官宣裁员 10000 人。分享一些我的建议给大家

大家好&#xff01;我是韩老师。昨天&#xff0c;西雅图双雄经历着不眠之夜。早些时间&#xff0c;就有传言说 1 月 18 日&#xff0c;亚马逊会裁员 18000 人。微软要裁员的各种消息也是满天飞。北京时间昨天晚上&#xff0c;微软官方博客发了一篇标题为 Focusing on our short…

10. 元组tuple类型详解

python3 tuple类型的使用 1. 基本知识 a. 元组&#xff08;tuple&#xff09;与列表类似, 不同之处在于元组的元素(项)不能修改。 b. 元组写在小括号 () 里&#xff0c;元素之间用逗号隔开。 c. 元组中的元素类型也可以不相同。 d. 构造包含0个或1个元素的元组比较特殊, 所以…

自增主键为什么不是连续的?

在前面文章中,我们提到过自增主键,由于自增主键可以让主键索引尽量地保持递增顺序插入,避免了页分裂,因此索引更紧凑。 之前我见过有的业务设计依赖于自增主键的连续性,也就是说,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不能保证连续递…

【深度学习数学基础之线性代数】研究使用链式法则进行反向传播的求导算法

链式法则 简单的说链式法则就是原本y对x求偏导&#xff0c;但是由于过程较为复杂&#xff0c;我们需要将函数进行拆分&#xff0c;通过链式进行分别求导&#xff0c;这样会使整个计算更为简单。 假设f k ( a b c ) f k(a bc)fk(abc) 通俗来说&#xff0c;链式法则表明&a…

宝贝代码部署笔记

记录前后端分离项目部署到云服务器 文章目录1. 启动数据库2. 创建数据库3. 阿里云开放后端项目端口4. 运行SQL文件5. 打包前端文件6. 服务端创建文件夹7. 打包后端jar包8. 安装配置Nginx服务器9. 启动Tomcat10. 项目文件上传部署1. 启动数据库 使用命令cd /opt/mysql/support-…

Generative Adversarial Network (GANs) 对抗神经网络 基础 第一部分

Generative Adversarial Network (GANs) 对抗神经网络 基础 第一部分 定义 Definition Discriminative model&#xff1a; Classifier 判别器Generative model: (random set of value , class) as input -> Create new features X 生成器 对抗神经网络模型主要就是通过判…

android的system域解耦

google很早在为此做准备&#xff0c;要求所有设备能够刷GSI&#xff08;通用系统镜像&#xff09;&#xff0c;并跑过XTS测试。动态分区解耦方案如上图。一、分区描述单一系统映像 (SSI)。包含system和system_ext图像的新概念图像。当这些分区对于一组目标设备是通用的时&#…

二叉树(一)

先简单了解一下树的概念&#xff0c;从而进一步了解二叉树&#xff0c;最后进行代码测试。树概念及结构(了解)在认识而二叉树之前我们首先了解一下树的概念。树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。…

图扑喜获第十一届中国创新创业大赛全国赛优秀奖!

在近期结束的第十一届中国创新创业大赛全国赛&#xff08;新一代信息技术&#xff09;比赛中&#xff0c;图扑软件喜获成长组优秀奖。这是继“创客中国”创新创业大赛优胜奖荣誉后&#xff0c;再一次对图扑软件在新一代信息技术领域专业的认可&#xff01;大赛围绕新一代信息技…

电机行业EDI案例分析

项目背景 J公司需要与国内某知名电机品牌Z公司建立EDI对接&#xff0c;J公司选择通过知行EDI系统与Z公司建立AS2连接&#xff0c;通过AS2接收Z公司发送过来的ORDERS&#xff08;采购订单&#xff09;和ORDCHG&#xff08;采购订单变更&#xff09;&#xff0c;并根据发接收到的…

Linux常见命令 15 - 权限管理命令 chmod

1. chmod 语法 chmod为修改文件/文件夹权限&#xff0c;有以下两种操作&#xff0c;其中-R表示递归修改 chmod {ugoa} {-} {rwx} [文件或目录] -Rchmod [mode421] [文件或目录] -R 2. chmod {ugoa} {-} {rwx} [文件或目录] -R u&#xff1a;文件或目录的所有者&#xff0c;g…

C++设计模式(5)——观察者模式

观察者模式 亦称&#xff1a; 事件订阅者、监听者、Event-Subscriber、Listener、Observer 意图 观察者模式是一种行为设计模式&#xff0c; 允许你定义一种订阅机制&#xff0c; 可在对象事件发生时通知多个 “观察” 该对象的其他对象。 问题 假如你有两种类型的对象&a…

概论第6章_正态总体的抽样分布_卡方分布_F分布_t分布

一 卡方分布 定义 设X1,X2,...,XnX_1, X_2,..., X_nX1​,X2​,...,Xn​ 独立同分布于标准正态分布N(0, 1), 则χ2X12...Xn2\chi^2X_1^2 ... X_n^2χ2X12​...Xn2​的分布称为 自由度为 n 的χ2\chi^2χ2分布&#xff0c; 记为χ2\chi^2χ2 ~ χ2(n)\chi^2(n)χ2(n) χ2\chi…

Python爬虫序章---爬取csdn作者排行榜

上篇文章介绍了requests库获取数据的基本方法&#xff0c;本篇文章利用自动化测试工具selenium进行数据抓取&#xff0c;也会对代码部分进行详细解释&#xff0c;以便小伙伴们能够更加理解和上手。 一.selenium技术介绍 Selenium是最广泛使用的开源 Web UI&#xff08;用户界面…

windows11远程连接Ubuntu桌面

如何通过Windows 11远程连接Ubuntu桌面 在日常开发过程中&#xff0c;很多时候是这样一种情形&#xff1a;一台装了Ubuntu系统的计算机作为远程服务器&#xff0c;开发人员则使用带Windows系统的计算机去连服务器进行开发。 连接服务器的方式有很多种&#xff0c;最简单的就是…

图扑软件荣获第十一届中国创新创业大赛全国赛优秀奖!

在近期结束的第十一届中国创新创业大赛全国赛&#xff08;新一代信息技术&#xff09;比赛中&#xff0c;图扑软件喜获成长组优秀奖。这是继“创客中国”创新创业大赛优胜奖荣誉后&#xff0c;再一次对图扑软件在新一代信息技术领域专业的认可&#xff01;大赛围绕新一代信息技…