抽象类 VS 接口
引言
接口和抽象类是面向对象编程(OOP, Object Oriented programming)中两个绕不开的概念,二者相似而又有所不同。接下来,我们来了解二者的概念并比较它们的异同。
什么是抽象类型?
抽象类是一种特殊的类,该类不能被实例化。抽象类的存在就是为了被继承,即抽象类可以被其它类继承但不能被实例化。那么,我们为什么需要一个无法被实例化的类呢?这样做的优点是,通过抽象类我们制定了一份强制所有子类必须遵守的合约,使所有子类有着一致的层次结构。抽象类提供了一种规范用于规定子类如何进行工作,子类可根据自身情况来重写抽象类中的抽象成员(及其它可被重写的成员)以满足自身需求。
抽象类作为一个基类,可以包含已实现的成员,同时应至少包含一个抽象成员,否则就没必要使用抽象类了。如果一个抽象类中仅仅包含抽象方法,那么这时抽象类就和接口很像了。
什么是接口?
接口中不能包含任何被实现的成员,即接口中只能包含成员的签名。如,没有方法体的方法、只包含访问器关键字(set、get)的属性等。和抽象类类似,接口也是一份合约。C#中,接口和抽象类的主要区别是,类可以实现多个接口,但只能继承一个(抽象)类。
比较异同
| 特征 | 接口 | 抽象类 |
|---|---|---|
| 是否支持多继承 | 支持 | 不支持 |
| 默认实现 | 接口中不能包含任何已实现的成员 | 抽象类中可以包含已实现(非抽象)的成员 |
| 访问修饰符 | 接口成员默认是公共(public)的,不再允许被任何访问修饰符修饰 | 抽象类成员可以被访问修饰符(不能是private)修饰 |
| 核心 VS 辅助 | 接口多用于定义(辅助性的)能力 | 抽象类多用于定义相同类型(这里类型不是数据类型的意思,解释见下文)子类所共有的一些特征 |
| 若只提供一些方法上的约束,建议使用接口 | 如果子类属于同一类型,且具有相同的行为或状态,建议使用抽象类提供约束 | |
| 寻找成员速度 | 相比抽象类较慢 | 相比接口更快 |
| 成员变动的影响 | 如果接口成员发生改动,则所有实现类都要进行改动 | 若向抽象类中添加非抽象成员,我们可以给该成员提供默认实现,这样子类就无需发生变动 |
| 允许包含的抽象成员 | 属性、方法、事件、索引器(这四类本质上都是方法) | 属性、方法、事件、索引器 |
| 是否允许定义字段 | 不允许 | 不允许定义使用abstract修饰的字段 |
抽象类是对子类的抽象,即将子类中的公共部分提取出来,放到一个特定的类中。抽象类是一份合约,用于为同一类型(这里类型不是指数据类型,而是逻辑上的划分,如人和猫都是动物)的子类提供约束。
接口也是一份合约,但接口多用对能力的定义,即用于指定实现类能做哪些事儿。

人和猫,都属于动物这个大类,我们可以抽象出二者的公共部分。如,年龄、体重、吃、会叫(用于形容人不太友好)等作为一个抽象类的成员。
abstract class Animal
{
public abstract int Age { set; get; }
public abstract float Weight { set; get; }
public abstract void Call();
//默认实现
public virtual void Eat()
{
Console.WriteLine("猫粮......");
}
} class Person : Animal
{
public override int Age { set; get; }
public override float Weight { set; get; } public override void Eat()
{
Console.WriteLine("鱼香肉丝盖饭......");
} public override void Call()
{
Console.WriteLine("雷好啊......");
}
} class Cat : Animal
{
public override int Age { set; get; }
public override float Weight { set; get; } public override void Call()
{
Console.WriteLine("喵喵喵......");
}
}
那么,只要继承Animal类的类都应属于动物这个大类,汽车就不应该继承Animal类。
此外,人和猫相比,人会制作工具而猫不行,那么制作工具的技能就是人所特有的,这时可以定义一个接口提供对制作工具这项技能的约束,然后让Person类实现该接口。
interface ICreatTool
{
void CreateTool();
} class Person : Animal, ICreatTool
{
public override int Age { set; get; }
public override float Weight { set; get; } public override void Eat()
{
Console.WriteLine("鱼香肉丝盖饭......");
} public override void Call()
{
Console.WriteLine("雷好啊......");
} public void CreateTool()
{
Console.WriteLine("造台MAC......");
}
}
再如,人、车、猫三者都可以跑,那么也可以定义个接口用于对跑这项技能提供约束。
interface IRun
{
void Run();
} class Person : IRun
{
public void Run()
{
Console.WriteLine("11路公交......");
}
} class Cat : IRun
{
public void Run()
{
Console.WriteLine("四蹄奔腾......");
}
} class Car : IRun
{
public void Run()
{
Console.WriteLine("四轮......");
}
}
小结
用简单的话概括接口和抽象类的异同:
抽象类和接口都是一种约束,这种约束使我们的代码有更好的层次结构,特别是在多人协同开发时(若每个人都按照自己的习惯来,对整个开发团队而言,开发成本不知要提高多少)。
抽象类是对相同类型(不是数据类型)子类公共部分的抽象(约束),接口是对能力的一种约束。
此外,建议大家读一读文末给出的这篇文章,本人读完收益颇多,本文中的表格部分引自该文。
参考文章
抽象类 VS 接口的更多相关文章
- java抽象类和接口
面向对象设计过程中重要的一点是如何进行抽象,即把"问题空间"中的元素与"方案空间"中的元素建立理想的一对一的映射关系.抽象类和接口便是抽象过程中的产物. ...
- php中抽象类与接口的概念以及区别
php里面的接口类,抽象类到底有什么用呢? 刚接触php的时候,觉得这个东西没什么用,其实这些东西还是有一定的作用的,下面我就简单的说说. 1.php 接口类:interface 其实他们的作用很简单 ...
- Java 抽象类与接口
接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 抽象类与接口是 Java 语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予 Java 强大的面向对象的能力.他们两者之间对 ...
- 浅谈我对C#中抽象类与接口的理解
C#中的抽象类与接口有些相似,初学者很容易混淆,今天就让我来谈谈对二者的理解. 首先我们得明确二者的含义,分述如下: 如果一个类不与具体的事物相联系,而只是表达一种抽象的概念,仅仅是作为其派生类的一个 ...
- Atitit 深入理解抽象类与接口 attilax总结
Atitit 深入理解抽象类与接口 attilax总结 1.1. 主要区别接口侧重于动作抽象..抽象类是属性名词抽象..1 1.2. 抽象层次类>>抽象类>>接口1 1.3. ...
- luogg_java学习_07_抽象类_接口_多态学习总结
这篇博客总结了半天,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 , 抽象 一种专门用来做父类,被继承的. (模板) 格式: abs ...
- PHP中抽象类,接口定义
这里先介绍接口,因为在我最近看的好几本php工具书中都没有提到抽象类. 本人也觉得,在理解了接口后抽象类也非常好理解. 例子代码随便写了一下.例子代码是很ok的,测试过了不会报错,懒得看代码的筒靴们看 ...
- 0026 Java学习笔记-面向对象-抽象类、接口
抽象方法与抽象类 抽象方法用abstract修饰,没有方法体部分,连花括号都不能有: 抽象方法和抽象类都用abstract修饰 包含抽象方法的类一定是抽象类:但不包含抽象方法的类也可以是抽象类 不能创 ...
- Java抽象类与接口的区别
很多常见的面试题都会出诸如抽象类和接口有什么区别,什么情况下会使用抽象类和什么情况你会使用接口这样的问题.本文我们将仔细讨论这些话题. 在讨论它们之间的不同点之前,我们先看看抽象类.接口各自的特性. ...
随机推荐
- 利用SQLServer数据库发送邮件
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 这个应用案例很多,一般都是预警,比如异常连接的时候,或者数据库报错的时候.等等,,, 先 ...
- 【.net 深呼吸】启动一个进程并实时获取状态信息
地球人和火星人都知道,Process类既可以获取正在运行的进程,也可以启动一个新的进程.在79.77%应用场合,我们只需要让目标进程顺利启动就完事了,至于它执行了啥,有没有出错,啥时候退出就不管了. ...
- iOS的ATS配置 - 2017年前ATS规定的适配
苹果规定 从2017年1月1日起,新提交的 app 不允许使用NSAllowsArbitraryLoads来绕过ATS(全称:App Transport Security)的限制. 以前为了能兼容ht ...
- Android性能优化之利用LeakCanary检测内存泄漏及解决办法
前言: 最近公司C轮融资成功了,移动团队准备扩大一下,需要招聘Android开发工程师,陆陆续续面试了几位Android应聘者,面试过程中聊到性能优化中如何避免内存泄漏问题时,很少有人全面的回答上来. ...
- C#泛型详解(转)
初步理解泛型: http://www.cnblogs.com/wilber2013/p/4291435.html 泛型中的类型约束和类型推断 http://www.cnblogs.com/wilber ...
- 计算Div标签内Checkbox个数或已被disabled的个数
先看下面的html: 计算div内的checkbox个数:$('#divmod input[type="checkbox"]').length 计算div内checkbox被dis ...
- ubuntu系统(华硕笔记本)屏幕亮度用Fn控制的调节设置
亲测配置: 系统:Linux lite 3.2 x86_64(Ubuntu其他版本可参考修改) 笔记本:华硕(asus)1201N 达到的效果: 可以正常使用Fn+F5调暗,Fn+F6调亮. 设置步骤 ...
- 记录在Windows上安装和使用Oracle数据库过程中的坑
1.安装Oracle Oracle软件是免费的,可以去官网下载相应的安装包.但是如果用于商业用途需要购买License.官网上针对各种平台,32位和64位都有,如果在Windows一般会下载到两个文件 ...
- UML类图(下):关联、聚合、组合、依赖
前言 上一篇文章UML类图(上):类.继承.实现,讲了UML类图中类.继承.实现三种关系及其在UML类图中的画法,本文将接着上文的内容,继续讲讲对象之间的其他几种关系,主要就是关联.聚合.组合.依赖, ...
- Linux Socket 原始套接字编程
对于linux网络编程来说,可以简单的分为标准套接字编程和原始套接字编程,标准套接字主要就是应用层数据的传输,原始套接字则是可以获得不止是应用层的其他层不同协议的数据.与标准套接字相区别的主要是要开发 ...