引言

接口和抽象类是面向对象编程(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("四轮......");
}
}

小结

用简单的话概括接口和抽象类的异同:

  • 抽象类和接口都是一种约束,这种约束使我们的代码有更好的层次结构,特别是在多人协同开发时(若每个人都按照自己的习惯来,对整个开发团队而言,开发成本不知要提高多少)。

  • 抽象类是对相同类型(不是数据类型)子类公共部分的抽象(约束),接口是对能力的一种约束。

此外,建议大家读一读文末给出的这篇文章,本人读完收益颇多,本文中的表格部分引自该文。

参考文章

Abstract Class versus Interface

版权声明

本文为作者原创,版权归作者雪飞鸿所有。 转载必须保留文章的完整性,且在页面明显位置处标明原文链接

如有问题, 请发送邮件和作者联系。

抽象类 VS 接口的更多相关文章

  1. java抽象类和接口

    面向对象设计过程中重要的一点是如何进行抽象,即把"问题空间"中的元素与"方案空间"中的元素建立理想的一对一的映射关系.抽象类和接口便是抽象过程中的产物.     ...

  2. php中抽象类与接口的概念以及区别

    php里面的接口类,抽象类到底有什么用呢? 刚接触php的时候,觉得这个东西没什么用,其实这些东西还是有一定的作用的,下面我就简单的说说. 1.php 接口类:interface 其实他们的作用很简单 ...

  3. Java 抽象类与接口

    接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 抽象类与接口是 Java 语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予 Java 强大的面向对象的能力.他们两者之间对 ...

  4. 浅谈我对C#中抽象类与接口的理解

    C#中的抽象类与接口有些相似,初学者很容易混淆,今天就让我来谈谈对二者的理解. 首先我们得明确二者的含义,分述如下: 如果一个类不与具体的事物相联系,而只是表达一种抽象的概念,仅仅是作为其派生类的一个 ...

  5. Atitit 深入理解抽象类与接口 attilax总结

    Atitit 深入理解抽象类与接口 attilax总结 1.1. 主要区别接口侧重于动作抽象..抽象类是属性名词抽象..1 1.2. 抽象层次类>>抽象类>>接口1 1.3. ...

  6. luogg_java学习_07_抽象类_接口_多态学习总结

    这篇博客总结了半天,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 , 抽象 一种专门用来做父类,被继承的. (模板) 格式: abs ...

  7. PHP中抽象类,接口定义

    这里先介绍接口,因为在我最近看的好几本php工具书中都没有提到抽象类. 本人也觉得,在理解了接口后抽象类也非常好理解. 例子代码随便写了一下.例子代码是很ok的,测试过了不会报错,懒得看代码的筒靴们看 ...

  8. 0026 Java学习笔记-面向对象-抽象类、接口

    抽象方法与抽象类 抽象方法用abstract修饰,没有方法体部分,连花括号都不能有: 抽象方法和抽象类都用abstract修饰 包含抽象方法的类一定是抽象类:但不包含抽象方法的类也可以是抽象类 不能创 ...

  9. Java抽象类与接口的区别

    很多常见的面试题都会出诸如抽象类和接口有什么区别,什么情况下会使用抽象类和什么情况你会使用接口这样的问题.本文我们将仔细讨论这些话题. 在讨论它们之间的不同点之前,我们先看看抽象类.接口各自的特性. ...

随机推荐

  1. CENTOS 6.5 平台离线编译安装 PHP5.6.6

    一.下载php源码包 http://cn2.php.net/get/php-5.6.6.tar.gz/from/this/mirror 二.编译 编译之前可能会缺少一些必要的依赖包,加载一个本地yum ...

  2. CodeSimth - .Net Framework Data Provider 可能没有安装。解决方法

    今天想使用CodeSimth生成一个sqlite数据库的模板.当添加添加数据库的时候发现: .Net Framework Data Provider 可能没有安装. 下面找到官方的文档说明: SQLi ...

  3. CoreCRM 开发实录——想用国货不容易

    昨天(2016年12月29日)发了开始开发的文章.本来晚上准备在 Coding.NET 上添加几个任务开始搞起了.可是真的开始用的时候才发现:Coding.NET 的任务功能只针对私有的任务开放.我想 ...

  4. ASP.NET Core的路由[1]:注册URL模式与HttpHandler的映射关系

    ASP.NET Core的路由是通过一个类型为RouterMiddleware的中间件来实现的.如果我们将最终处理HTTP请求的组件称为HttpHandler,那么RouterMiddleware中间 ...

  5. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  6. 拼图小游戏之计算后样式与CSS动画的冲突

    先说结论: 前几天写了几个非常简单的移动端小游戏,其中一个拼图游戏让我郁闷了一段时间.因为要获取每张图片的位置,用`<style>`标签写的样式,直接获取计算后样式再用来交换位置,结果就悲 ...

  7. ASP.NET MVC——模型绑定

    这篇文章我们来讲讲模型绑定(Model Binding),其实在初步了解ASP.NET MVC之后,大家可能都会产生一个疑问,为什么URL片段最后会转换为例如int型或者其他类型的参数呢?这里就不得不 ...

  8. ubuntu 下安装scrapy

    1.把Scrapy签名的GPG密钥添加到APT的钥匙环中: sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 6272 ...

  9. BPM体系文件管理解决方案分享

    一.方案概述 企业管理在很大程度上是通过文件化的形式表现出来,体系文件管理是管理体系存在的基础和证据,是规范企业管理活动和全体人员行为,达到管理目标的管理依据.对与公司质量.环境.职业健康安全等体系有 ...

  10. kvm 使用入门详解

    kvm 是虚拟化技术的一个典型实现,功能非常强大,使用很方便.kvm 本身主要实现对 CPU 的虚拟化,内存和IO的虚拟化使用了开源软件 qemu,qemu 是纯软件层面的虚拟化,其实就是个模拟器.k ...