Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >为什么在多态性中同时使用基类和接口?

为什么在多态性中同时使用基类和接口?
EN

Stack Overflow用户
提问于 2008-12-18 13:12:14
回答 7查看 770关注 0票数 1

在多态性的C#示例中,有一个Cat类,它继承了一个名为AnimalBase的类和一个名为IAnimal的接口。

有问题的链接是:http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming

我的问题是,为什么同时使用基类和接口?为什么不是其中之一呢?我的想法是,实现多态性只需要一个抽象类。

谢谢

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2008-12-18 14:10:26

“从基类继承允许你继承行为,而实现一个接口只允许你指定交互”这句话是绝对正确的。

但更重要的是,接口允许静态类型语言继续支持多态性。面向对象的纯化论者会坚持认为,一种语言应该提供继承、封装、模块化和多态性,以便成为一种功能齐全的面向对象语言。在动态类型或鸭子类型的语言(如Smalltalk )中,多态性是微不足道的;然而,在静态类型语言(如Java或C# )中,多态性远非微不足道(实际上,从表面上看,它似乎与强类型的概念不一致)。

让我来演示一下:

在动态类型(或鸭子类型)语言(如Smalltalk)中,所有变量都是对对象的引用(仅此而已)。所以,在Smalltalk中,我可以这样做:

代码语言:javascript
运行
AI代码解释
复制
|anAnimal|    
anAnimal := Pig new.
anAnimal makeNoise.

anAnimal := Cow new.
anAnimal makeNoise.

该代码:

  1. 声明了一个名为anAnimal的本地变量(请注意,我们没有指定变量的类型-所有变量都是对对象的引用,不多也不少。)
  2. 创建了一个名为“anAnimal”的类的新实例。
  3. 将该新实例分配给变量,并将消息makeNoise分配给猪。
  4. 使用奶牛重复整个过程,但将其分配给与猪完全相同的变量。<代码>H212<代码>G213

相同的Java代码看起来像这样(假设Duck和Cow是Animal的子类:

代码语言:javascript
运行
AI代码解释
复制
Animal anAnimal = new Pig();
duck.makeNoise();

anAnimal = new Cow();
cow.makeNoise();

这一切都很好,直到我们介绍类蔬菜。蔬菜和动物有一些相同的行为,但不是全部。例如,动物和蔬菜可能都能生长,但很明显蔬菜不会发出噪音,动物也不能收获。

在Smalltalk中,我们可以这样写:

代码语言:javascript
运行
AI代码解释
复制
|aFarmObject|
aFarmObject := Cow new.
aFarmObject grow.
aFarmObject makeNoise.

aFarmObject := Corn new.
aFarmObject grow.
aFarmObject harvest.

这在Smalltalk中工作得很好,因为它是鸭子类型的(如果它走起来像鸭子,叫起来像鸭子-它就是鸭子)。在这种情况下,当消息被发送到对象时,将在接收方的方法列表上执行查找,如果找到匹配的方法,则调用该方法。如果不是,就会抛出某种NoSuchMethodError异常--但这一切都是在运行时完成的。

但是在Java这种静态类型的语言中,我们可以为变量分配什么类型呢?玉米需要从蔬菜中继承,以支持生长,但不能从动物中继承,因为它不会制造噪音。Cow需要从Animal继承以支持makeNoise,但不能从蔬菜继承,因为它不应该实现收割。看起来我们需要多重继承--从多个类继承的能力。但事实证明,这是一个相当困难的语言特性,因为出现了所有的边缘情况(当多个并行超类实现相同的方法时会发生什么?)

随之而来的是接口...

如果我们创建Animal和declare类,每个类都实现Growable,我们就可以声明我们的Cow是Animal,我们的玉米是蔬菜。我们也可以声明动物和蔬菜都是可生长的。这让我们可以写这段代码来增长一切:

代码语言:javascript
运行
AI代码解释
复制
List<Growable> list = new ArrayList<Growable>();
list.add(new Cow());
list.add(new Corn());
list.add(new Pig());

for(Growable g : list) {
   g.grow();
}

它让我们这样做,制造动物的声音:

代码语言:javascript
运行
AI代码解释
复制
List<Animal> list = new ArrayList<Animal>();
list.add(new Cow());
list.add(new Pig());
for(Animal a : list) {
  a.makeNoise();
}

鸭型语言的最大优点是您获得了非常好的多态性:类提供行为所需做的全部工作就是提供方法(还有其他权衡,但这是讨论类型时最重要的权衡)。只要每个人都表现得很好,并且只发送与定义的方法匹配的消息,一切都是好的。缺点是下面的那种错误直到运行时才会被捕获:

代码语言:javascript
运行
AI代码解释
复制
|aFarmObject|
aFarmObject := Corn new.
aFarmObject makeNoise. // No compiler error - not checked until runtime.

静态类型的语言提供了更好的“契约式编程”,因为它们将在编译时捕获以下两种错误:

代码语言:javascript
运行
AI代码解释
复制
Animal farmObject = new Corn();  // Compiler error: Corn cannot be cast to Animal.
farmObject makeNoise();

--

代码语言:javascript
运行
AI代码解释
复制
Animal farmObject = new Cow();
farmObject.harvest(); // Compiler error: Animal doesn't have the harvest message.

So....to总结:

  1. 接口实现允许您指定对象可以做的事情种类(交互),而类继承允许您指定应该如何完成操作(implementation).
  2. Interfaces为我们提供了许多“真实”多态性的好处,而无需牺牲编译器类型检查。
票数 7
EN

Stack Overflow用户

发布于 2008-12-18 13:15:19

当您想要重用行为时,可以使用基类

当您想要控制类如何与其他对象交互时,可以使用接口。它以精确的方式定义了交互。

根据我的经验,当你想要重用行为的时候,你想要控制类如何交互的次数就相形见绌了。

票数 7
EN

Stack Overflow用户

发布于 2008-12-18 13:15:51

拥有一个抽象类可以让你以一种通用的方式实现一些/大多数成员。拥有接口意味着当您想要将其用于多态性时,您不再局限于仅使用该抽象基类。

我看不出两者兼得有什么矛盾。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/379282

复制
相关文章
MySQL ORDER BY,GROUPBY 与各种JOIN
在 SQL 中增加 HAVING 子句原因是,WHERE 关键字无法与合计函数一起使用。
泰坦HW
2020/07/22
2K0
MySQL索引优化order by与group by
MySQL索引优化order by与group by 案例一 name符合最左前缀法则,但在age处断了,所以只能用到name列,索引长度202,order by也用到了index_union索引 树,通过Extra可看出。 案例二 where后符合最左前缀,所以只用到了name列,而order by处不是用的索引树index_union,因为age还没排序呢, position排序肯定是乱的,需要将结果集放在内存中排序。 案例三 如第二张图所示,在确定最左列name后,其实下面
晓果冻
2022/09/08
6380
MySQL索引优化order by与group by
Mysql order by 优化
本节描述MySQL何时可以使用索引来满足ORDER BY子句,当不能使用索引时使用filesort,以及优化器中有关ORDER BY的执行计划信息。
XING辋
2019/03/26
1.5K0
zend studio 8安装与汉化
正确操作: 1、大家可以用这个地址作为更新源(操作:菜单栏中window->property->Installation/update->update 添加这个地址,并打勾)
Java架构师必看
2021/03/22
4710
【mysql】order by排序
排序数据 1. 排序规则 如果没有使用排序操作,默认情况下查询返回的数据是按照添加数据的顺序显示的。 使用 ORDER BY 对查询到的数据进行排序操作。 使用 ORDER BY 子句排序 ASC(ascend): 升序 DESC(descend):降序 ORDER BY 子句在SELECT语句的结尾。 2. 单列排序 按照salary从高到低的顺序显示员工信息 SELECT employee_id,last_name,salary FROM employees ORDER BY salary DESC;
兮动人
2022/03/03
2.5K0
PHP 扩展与 ZEND 引擎的整合
PHP 扩展是对 PHP 功能的一个补充,编写完 PHP 扩展以后, ZEND 引擎需要获取到 PHP 扩展的信息,比如 phpinfo() 函数是如何列出 PHP 扩展的信息,PHP 扩展中的函数如何提供给 PHP 程序员使用,这些是开发 PHP 扩展需要了解的内容。
码农UP2U
2020/08/26
7430
MySQL ORDER BY IF() 条件排序
在做sqlzoo的时候,碰到一个SQL的排序问题,他把符合条件的单独几行,可以放在查询结果的开始,或者查询结果的尾部
用户7657330
2020/08/14
3.9K0
MySQL ORDER BY IF() 条件排序
[1009]mysql中Cast()函数的用法
来源:https://blog.csdn.net/m0_37450089/article/details/80750994
周小董
2021/06/29
2K0
MySQL Order By工作原理
Extra中包含Using filesort表示需要排序,在排序时,MySQL会为每个线程分配一块内存区域用于排序,称之为sort_buffer。
shysh95
2022/02/16
8370
MySQL Order By工作原理
MySQL——优化ORDER BY语句
本篇文章我们将了解ORDER BY语句的优化,在此之前,你需要对索引有基本的了解,不了解的老少爷们可以先看一下我之前写过的索引相关文章。现在让我们开始吧。
撸码那些事
2018/10/08
1.2K0
MySQL——优化ORDER BY语句
Mysql order by排序优化
1. 加大max_length_for_sort_data参数的设置 在MySQL中,排序算法分为两种,一是只加载排序字段到内存,排序完成后再到表中取其他字段,二是加载所有需要的字段到内存,显然第二种节省了IO操作,所以更快 决定使用哪种算法是通过参数max_length_for_sort_data来决定的 当所有返回字段的最大长度小于这个参数值时,MySQL就会选择第二种算法,反之使用第一种。所以,如果有充足的内存让MySQL存放须要返回的非排序字段,就可以加大这个参数的值来让MySQL选择第二种排序算法
dys
2018/04/02
2.5K0
mysql order by的坑
结论:当我们需要按照多个字段排序时,我们需要显式的指出每个字段的排序方式。 1.下面两条语句的结果是一样的 SELECT *from issue_info ORDER BY create_time ,
IT云清
2019/01/22
8560
C++ const_cast static_cast dynamic_cast reinterpret_cast
对static限定的改变必然会造成范围性的影响,而const限定的只是变量或对象自身
jasong
2021/10/13
5280
static_cast const_cast reindivter_cast dynamic_cast
C 风格(C-style)强制转型如下: (T) exdivssion // cast exdivssion to be of type T 函数风格(Function-style)强制转型使用这样的语法: T(exdivssion) // cast exdivssion to be of type T 这两种形式之间没有本质上的不同,它纯粹就是一个把括号放在哪的问题。我把这两种形式称为旧风格(old-style)的强制转型。 使用标准C++的类型转换符:static_cast 、dynamic_cast、
用户1154259
2018/01/17
8630
Zend_string与写时复制
学习过C语言的应该知道,字符串中除了最后一个字符外不允许含有\0,否则会被认为是字符串的结束字符,这就导致了C语言的字符串有很多的限制,比如不存储图片、文件等二进制数据。但是PHP就没有这样的限制,它的字符串可以存储二进制数据,并不会出现任何报错,而PHP的这种能力就叫做字符串的二进制安全 c语言代码片段
程序员小饭
2020/09/07
6710
Mysql(9)——排序的方法order by与limit的用法
其中,order by即按照升序或者降序的方式排列,如果后面跟的是desc则是降序排列,如果后面跟的是asc,则是升序排列。
gzq大数据
2020/11/11
1.3K0
Mysql(9)——排序的方法order by与limit的用法
MySQL中的ORDER BY field
MySQL可以通过field()函数自定义排序,格式:field(value,str1,str2,str3,str4),value与str1、str2、str3、str4比较,返回1、2、3、 4,如遇到null或者不在列表中的数据则返回0. 这个函数好像Oracle中没有专门提供(也可能是我没有用到),不过自己实现这样一个函数还是比较 简单的。
用户7657330
2020/08/14
3.3K0
Mysql如何使用order by工作
日常开发中,我们经常要进行字段的排序,但是我们大多不知道排序是如何执行的,今天我们就说说order by 的执行逻辑,
小土豆Yuki
2020/11/03
1.1K0
mysql使用ORDER BY和GROUP BY
今天写代码时遇到一个需求是这样的: 取表内最新的一条数据,根据用户名分组 本来以为又是那种 需求,然后就开始写sql,写完一运行,报错。。。 然后发现GROUP BY必须放在ORDER BY的前面 但这样又会导致不能取最新的一条数据 于是用了一个“子查询”的办法解决 <select id="cowBeer" resultType="map" parameterType="map"> SELECT [字段] FROM ( SELECT DISTINCT
阿超
2022/08/16
9390
mysql使用ORDER BY和GROUP BY
mysql随机排序 order by rand()
@Query("SELECT a from #{#entityName} a where a.isDeleted=0 and a.sourceType=1 order by rand()") fun findGankAll(pageable: Pageable): Page<Image> @Query("SELECT a from #{#entityName} a where a.sourceType=1 and a.isDeleted=0 and a.category like %:searchTex
一个会写诗的程序员
2018/08/17
2.1K0

相似问题

mysql by order by case when cast()

20

Linq order by with cast as

20

字段名“order”与mysql与Zend_Db_table_Abstract冲突?

14

jpa openjpa - order by with cast

11

在具有多个SELECT或ORDER变量的SELECT查询(或ORDER )中使用MySql CAST函数

20
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档