接口和抽象类有什么区别?

接口和抽象类到底有什么区别?

1357193 次浏览

可以在这里找到解释:http://www.developer.com/lang/php/article.php/3604111/PHP-5-OOP-Interfaces-Abstract-Classes-and-the-Adapter-Pattern.htm

抽象类是一个类,它是仅部分由程序员。它可能包含一个或多个抽象方法抽象方法只是一个函数定义用来告诉程序员方法必须在子进程中实现类。

接口类似于抽象类;确实接口占据了与类和抽象相同的命名空间因为这个原因,你不能定义一个同名的接口作为一个类。接口是一个完全抽象类;它的任何方法被实现,而不是一个类从它的子类,据说实现该接口。

无论如何,我发现接口的这种解释有点令人困惑。更常见的定义是:接口定义了实现类必须履行的契约。接口定义由公共成员的签名组成,没有任何实现代码。

接口

接口是合同:编写接口的人说“嘿,我接受这样的事情”,使用接口的人说“好吧,我写的类看起来是这样的”。

接口是一个空壳。只有方法的签名,这意味着方法没有主体。接口什么也做不了。这只是一个模式。

例如(伪代码):

// I say all motor vehicles should look like this:interface MotorVehicle{void run();
int getFuel();}
// My team mate complies and writes vehicle looking that wayclass Car implements MotorVehicle{
int fuel;
void run(){print("Wrroooooooom");}

int getFuel(){return this.fuel;}}

实现一个接口消耗很少的CPU,因为它不是一个类,只是一堆名称,因此不需要进行任何昂贵的查找。在重要的时候,比如在嵌入式设备中,这是很好的。


抽象类

与接口不同,抽象类是类。它们的使用成本更高,因为当您从它们继承时需要进行查找。

抽象类看起来很像接口,但它们有更多的东西:您可以为它们定义行为。它更多的是关于一个人说“这些类应该看起来像这样,它们有共同之处,所以填空!”。

例如:

// I say all motor vehicles should look like this:abstract class MotorVehicle{
int fuel;
// They ALL have fuel, so lets implement this for everybody.int getFuel(){return this.fuel;}
// That can be very different, force them to provide their// own implementation.abstract void run();}
// My teammate complies and writes vehicle looking that wayclass Car extends MotorVehicle{void run(){print("Wrroooooooom");}}

实施

虽然抽象类和接口应该是不同的概念,但实现有时会使该声明不真实。有时,它们甚至不是你想象的那样。

在Java,这个规则是严格执行的,而在PHP中,接口是没有声明方法的抽象类。

在Python中,抽象类更多的是一种编程技巧,你可以从ABC模块中获得,实际上是使用元类,因此也是类。在这种语言中,接口更多地与鸭子类型相关,它是约定和调用描述符的特殊方法(__method__方法)的混合。

和编程一样,有另一种语言的理论、实践和实践:-)

不是原始问题的答案,但是一旦你有了它们之间差异的答案,你将进入何时使用每个困境:什么时候使用接口或抽象类?什么时候同时使用两者?

我对OOP的了解有限,但是直到现在,将接口视为语法中的形容词的等价物一直对我有效(如果这种方法是假的,请纠正我!)。例如,接口名称就像你可以赋予类的属性或功能,一个类可以有许多属性或功能:ISerializable、ICountable、IList、ICacheable、IHappy、…

抽象类接口之间的关键技术差异是:

  • 抽象类可以有常量、成员、方法存根(没有主体的方法)和定义的方法,而接口只能有常量方法存根

  • 抽象类的方法和成员可以用任何可见性定义,而接口的所有方法都必须定义为public(默认情况下它们是公共定义的)。

  • 继承抽象类时,具体子类必须定义抽象方法,而抽象类可以扩展另一个抽象类,并且不必定义父类的抽象方法。

  • 类似地,扩展另一个接口的接口不负责从父接口实现方法。这是因为接口不能定义任何实现。

  • 子类只能扩展单个类(抽象或具体),而接口可以扩展或类可以实现多个其他接口

  • 子类可以定义具有相同或更少限制性可见性的抽象方法,而实现接口的类必须定义具有完全相同可见性(公共)的方法。

让我们再次研究这个问题:

首先要让你知道的是,1/1和1*1的结果是一样的,但这并不意味着乘法和除法是一样的。显然,它们有一些很好的关系,但请注意,你们两个是不同的。

我将指出主要的区别,其余的已经解释过了:

抽象类对于建模类层次结构很有用。乍一看任何需求,我们都部分清楚完全要构建什么,但我们知道建什么。所以你的抽象类就是你的基类。

接口对于让其他层次结构或类知道我能做什么很有用。当你说我能做某事时,你必须有这种能力。接口会将其标记为类实现相同功能的强制性。

当您想在继承层次结构中提供多态行为时,请使用抽象类。

当您想要完全不相关的类的多态行为时,请使用接口。

一些重要的区别:

以桌子的形式:

差异

来自javap的Joe

1.主要区别在于Java接口的方法是隐式抽象的,不能有实现有实现默认行为的实例方法。

2.Java接口中声明的变量默认为Final。抽象类可以包含非Final变量。

3.默认情况下,Java接口的成员是公共的。Java抽象类可以具有类成员的常见风格,例如Private、保护等等

4.Java接口应该使用关键字“implements”来实现;Java抽象类应该使用关键字“扩展”来扩展。

一个接口只能扩展另一个Java接口,抽象类可以扩展另一个Java类并实现多个Java接口。

6.一个Java类可以实现多个接口,但只能扩展一个抽象类。

7.接口是绝对抽象的,不能被实例化;一个Java抽象类也不能被实例化,但可以被调用,如果main()存在。

8.与java抽象类相比,java接口很慢,因为它需要额外的间接。

在一个接口中,所有的方法都必须只是定义,而不应该实现单个方法。

但是在抽象类中必须有一个只有定义的抽象方法,但其他方法也可以在抽象类中实现。

继承用于两个目的:

  • 允许对象将父类型数据成员和方法实现视为自己的。

  • 允许期望对超类型对象的引用的代码使用对一种类型的对象的引用。

在支持广义多重继承的语言/框架中,通常不需要将类型分类为“接口”或“抽象类”。然而,流行的语言和框架允许一种类型将另一种类型的数据成员或方法实现视为自己的,即使它们允许一种类型可替换任意数量的其他类型。

抽象类可以有数据成员和方法实现,但只能被不从任何其他类继承的类继承。接口对实现它们的类型几乎没有限制,但不能包括任何数据成员或方法实现。

有些时候,类型可以替代许多不同的东西;还有一些时候,对象将父类型数据成员和方法实现视为自己的东西是有用的。区分接口和抽象类允许在最相关的情况下使用这些能力。

接口只包含功能的定义/签名,如果我们有一些通用的功能和通用签名,那么我们需要使用一个抽象类。通过使用抽象类,我们可以同时提供行为和功能。另一个继承抽象类的开发人员可以轻松使用这个功能,因为他们只需要填写空白。

在此处输入图像描述图片来源:

http://www.dotnetbull.com/2011/11/difference-between-abstract-class-and.html

http://www.dotnetbull.com/2011/11/what-is-abstract-class-in-c-net.htmlhttp://www.dotnetbull.com/2011/11/what-is-interface-in-c-net.html

我正在建造一座300层的大楼

建筑的蓝图接口

  • 例如,Servlet(I)

建筑高达200层-部分完成---抽象

  • 部分实现,例如泛型和HTTP servlet

建筑施工完成-具体

  • 完全实现,例如,自己的servlet

接口

  • 我们对实现一无所知,只知道需求。我们可以去一个接口。
  • 默认情况下,每个方法都是公共和抽象的
  • 它是一个100%纯抽象类
  • 如果我们声明公共,我们就不能声明私有和受保护
  • 如果我们声明抽象,我们就不能声明Final、静态、同步、严格的fp和本机
  • 每个接口都有public、静态和Final
  • 序列化和瞬态不适用,因为我们无法为in接口创建实例
  • 非易失性,因为它是最终的
  • 每个变量都是静态的
  • 当我们在接口中声明变量时,我们需要在声明时初始化变量
  • 不允许实例和静态块

摘要

  • 部分执行
  • 它有一个抽象的方法。一个附加,它使用具体
  • 对抽象类方法修饰符没有限制
  • 对抽象类变量修饰符没有限制
  • 除了抽象,我们不能声明其他修饰符
  • 初始化变量没有限制

摘自DurgaJobs网站

其实很简单。

您可以将接口视为只允许有抽象方法而不允许有其他方法的类。

因此,接口只能“声明”而不能定义您希望类具有的行为。

抽象类允许您声明(使用抽象方法)以及定义(使用完整方法实现)您希望类具有的行为。

常规类只允许您定义,而不是声明您希望类具有的行为/操作。

最后一件事,

在Java,您可以实现多个接口,但只能扩展一个(抽象类或类)。

这意味着定义行为的继承被限制为每个类只允许一个……即如果你想要一个封装了类A、B和C行为的类,你需要执行以下操作:类A扩展B,类C扩展A……它有点绕来绕去的方式有多个继承……

接口另一方面,你可以简单地做:接口C实现A,B

所以实际上Java只在“声明的行为”即接口中支持多重继承,并且只支持具有定义行为的单一继承……除非你按照我描述的方式进行……

希望这有道理。

接口与抽象类的比较是错误的。应该有另外两个比较:1)接口与类和2)抽象与最终类

接口与类

接口是两个对象之间的契约。例如,我是邮递员,你是要投递的包裹。我希望你知道你的送货地址。当有人给我一个包裹时,它必须知道它的送货地址:

interface Package {String address();}

是一组遵守契约的对象。例如,我是“Box”组中的一个盒子,我遵守邮递员要求的契约。同时我遵守其他契约:

class Box implements Package, Property {@OverrideString address() {return "5th Street, New York, NY";}@OverrideHuman owner() {// this method is part of another contract}}

抽象vs最终

抽象类是一组不完整的对象。它们不能被使用,因为它们错过了一些部分。例如,我是一个抽象的GPS感知框-我知道如何检查我在地图上的位置:

abstract class GpsBox implements Package {@Overridepublic abstract String address();protected Coordinates whereAmI() {// connect to GPS and return my current position}}

这个类,如果被另一个类继承/扩展,可能非常有用。但就其本身而言-它是无用的,因为它不能有对象。抽象类可以构建最终类的元素。

最后一堂课是一组完整的对象,可以使用,但不能修改。他们确切地知道如何工作和做什么。例如,我是一个Box,在构建过程中总是去指定的地址:

final class DirectBox implements Package {private final String to;public DirectBox(String addr) {this.to = addr;}@Overridepublic String address() {return this.to;}}

在大多数语言中,比如Java或C++,可以有只是一个类,既不是抽象的也不是最终的。这样的类可以被继承,也可以被实例化。虽然我不认为这严格符合面向对象的范式。

同样,将接口与抽象类进行比较是不正确的。

唯一的区别是一个可以参与多重继承,而另一个不能。

接口的定义随着时间的推移而改变。你认为接口只有方法声明和契约吗?Java8之后的静态最终变量和默认定义呢?

接口被引入Java是因为的钻石问题具有多重继承,这就是他们实际上打算做的。

接口是为解决多重继承问题而创建的构造,可以具有抽象方法、默认定义和静态最终变量。

为什么Java允许静态的最终变量在接口时,他们只是为了契约?

主要的一点是:

  • 它提供了“对象”应该拥有的基本数据和/或它应该能够执行的功能。它关心对象的基本特征:它拥有什么和它能做什么。因此,从同一个抽象类继承的对象共享基本特征(泛化)。
  • 界面面向功能。它定义了一个对象应该具有的功能。不管它是什么对象,只要它能完成这些在接口中定义的功能,就没问题。它忽略了其他一切。一个对象/类可以包含多个(组)功能;因此一个类有可能实现多个接口。

核心进展:

  • 抽象类可以有属性、数据字段、方法(完整/不完整)。
  • 如果方法或属性以抽象关键字定义,则必须在派生类中重写。(功能)
  • 如果为抽象类中的方法或属性定义抽象关键字,则无法定义方法主体并为其获取/设置值必须在派生类中重写的属性。
  • 抽象类不支持多重继承。
  • 抽象类包含构造函数。
  • 抽象类可以包含子类、函数、属性的访问修饰符。
  • 只有抽象类的完全成员可以是静态的。
  • 接口只能从另一个接口继承,不能从抽象类继承,抽象类可以从另一个抽象类或另一个接口继承。

优势:

  • 它是一种契约,强制所有子类执行相同的层次结构或标准。
  • 如果不同的实现是同类的,并且使用共同的行为或状态,那么抽象类更适合使用。
  • 如果我们向抽象类添加一个新方法,那么我们可以选择提供默认实现,因此所有现有代码都可以正常工作。
  • 它允许比接口更快的执行。(接口需要更多的时间在相应的类中找到实际的方法。)
  • 它可以用于紧耦合和松耦合。

点击这里查看详情。http://pradeepatkari.wordpress.com/2014/11/20/interface-and-abstract-class-in-c-oops/

我不想强调差异,这些差异已经在许多答案中说过了(关于接口中变量的公共静态最终修饰符和抽象类中受保护的私有方法的支持)

简单地说,我想说:

接口说明:通过多个不相关的对象实现合约

抽象类:在多个相关对象之间实现相同或不同的行为

从Oracle留档

考虑使用抽象类如果:

  1. 您希望在几个密切相关的类之间共享代码。
  2. 您希望扩展抽象类的类具有许多通用方法或字段,或者需要公共(例如protected和Private)以外的访问修饰符。
  3. 您想声明非静态或非最终字段。

考虑使用接口如果:

  1. 你期望不相关的类会实现你的接口。例如,许多不相关的对象可以实现Serializable接口。
  2. 您希望指定特定数据类型的行为,但不关心谁实现其行为。
  3. 您想利用类型的多重继承。

抽象类建立与具体类的“是”关系。接口为类提供“有”能力。

如果您正在寻找Java作为编程语言,这里还有一些更新:

Java8通过提供default方法特性,在一定程度上缩小了interfaceabstract类之间的差距。

有关详细信息,请参阅此留档页面

查看这个SE问题以获取代码示例以更好地理解。

我应该如何解释接口和抽象类之间的区别?

在此处输入图片描述

这是对接口与抽象类的一个非常基本的理解。

总结它的最短方法是interface是:

  1. 完全抽象,除了defaultstatic方法;虽然它有defaultstatic方法的定义(方法签名+实现),但它只有其他方法的声明(方法签名)。
  2. 受制于比类更宽松的规则(一个类可以实现多个interface,并且interface可以从多个interface继承)。所有变量都是隐式常量,无论是否指定为public static final。所有成员都是隐式public,无论是否指定为4。
  3. 通常用于保证实现类将具有指定的功能和/或与实现相同接口的任何其他类兼容。

同时,一个abstract类是:

  1. 从完全抽象到完全实现,倾向于有一个或多个abstract方法。可以包含声明和定义,声明标记为abstract
  2. 一个成熟的类,受制于管理其他类的规则(只能从一个类继承),条件是它不能实例化(因为不能保证它已经完全实现)。可以有非常量成员变量。可以实现成员权限改造,限制成员为protectedprivate或私有包(未指定)。
  3. 通常用于提供可以由多个子类共享的尽可能多的实现,或者提供程序员能够提供的尽可能多的实现。

或者,如果我们想把它归结为一句话:interface是实现类已经,但abstract类是子类

接口一般是没有逻辑只有签名的类。抽象类是有逻辑的类。两者都支持契约作为接口,所有方法都应该在子类中实现,但抽象地只应该实现抽象方法。什么时候使用接口,什么时候抽象?为什么使用接口?

class Circle {
protected $radius;
public function __construct($radius)
{$this->radius = $radius}
public function area(){return 3.14159 * pow(2,$this->radius); // simply pie.r2 (square);}
}
//Our area calculator class would look like
class Areacalculator {
$protected $circle;
public function __construct(Circle $circle){$this->circle = $circle;}
public function areaCalculate(){return $circle->area(); //returns the circle area now}
}

我们只会做

$areacalculator = new Areacalculator(new Circle(7));

几天后,我们需要矩形、正方形、四边形等区域。如果是这样,我们必须每次更改代码并检查实例是正方形、圆形还是矩形?现在OCP说的是接口代码而不是实现。解决方法:

Interface Shape {
public function area(); //Defining contract for the classes
}
Class Square implements Shape {
$protected length;
public function __construct($length) {//settter for length like we did on circle class}
public function area(){//return l square for area of square}
Class Rectangle implements Shape {
$protected length;$protected breath;
public function __construct($length,$breath) {//settter for length, breath like we did on circle,square class}
public function area(){//return l*b for area of rectangle}
}

现在为面积计算器

class Areacalculator {
$protected $shape;
public function __construct(Shape $shape){$this->shape = $shape;}
public function areaCalculate(){return $shape->area(); //returns the circle area now}
}
$areacalculator = new Areacalculator(new Square(1));$areacalculator->areaCalculate();
$areacalculator = new Areacalculator(new Rectangle(1,2));$areacalculator->;areaCalculate();

这不是更灵活吗?如果我们在没有接口的情况下编码,我们会检查每个形状的实例的冗余代码。

什么时候使用抽象?

Abstract Animal {
public function breathe(){
//all animals breathe inhaling o2 and exhaling co2
}
public function hungry() {
//every animals do feel hungry
}
abstract function communicate();// different communication style some bark, some meow, human talks etc
}

现在,当不需要该类的实例时,应该使用抽象,具有类似的逻辑,需要契约。

许多初级开发人员犯了一个错误,他们认为接口、抽象类和具体类是同一事物的微小变化,并纯粹出于技术原因选择其中一个:

接口和抽象类虽然从技术角度看是相似的,但却具有完全不同的含义和目的。

总结

  1. 接口定义了一个契约,一些实现将为您实现

  2. 抽象类提供了实现可以重用的默认行为

备选摘要

  1. 接口用于定义公共API
  2. 抽象类用于内部使用,并用于定义SPI

关于隐藏实现细节的重要性

具体类以非常具体的方式完成实际工作。例如,ArrayList使用连续的内存区域以紧凑的方式存储对象列表,提供快速随机访问、迭代和就地更改,但不擅长插入、删除,有时甚至是添加;同时,LinkedList使用双链节点存储对象列表,提供快速迭代、就地更改和插入/删除/添加,但不擅长随机访问。这两种类型的列表针对不同的用例进行了优化,如何使用它们非常重要。当您试图从与您进行大量交互的列表中挤出性能时,当选择列表类型取决于您时,您应该仔细选择要实例化的列表。

另一方面,列表的高级用户并不关心它实际上是如何实现的,他们应该与这些细节绝缘。假设Java没有暴露List接口,而是只有一个具体的List类,而这个类实际上就是现在的LinkedList。所有Java开发人员都会定制他们的代码以适应实现细节:避免随机访问,添加缓存以加快访问速度,或者只是自己重新实现ArrayList,尽管它与所有其他实际仅适用于List的代码不兼容。那将是可怕的…但是现在想象一下,Java的主人实际上意识到链表对于大多数实际用例来说是可怕的,并决定切换到他们唯一可用的List类的数组列表。这将影响世界上每个Java程序的性能,人们不会对此感到高兴。罪魁祸首是实现细节可用,开发人员认为这些细节是他们可以依赖的永久契约。这就是为什么隐藏实现细节,只定义抽象契约很重要。这就是接口的目的:定义一个方法接受什么样的输入,以及期望什么样的输出,而不会暴露所有的勇气,这些勇气会诱使程序员调整他们的代码以适应可能随着未来任何更新而变化的内部细节。

抽象类介于接口和具体类之间。它的作用是帮助实现共享普通或无聊的代码。例如,AbstractCollectionisEmpty提供了基于大小为0的基本实现,contains提供了迭代和比较,addAll提供了重复的add等。这让实现专注于区分它们的关键部分:如何实际存储和检索数据。

api与spi

代码不同部分之间的接口是低内聚的。它们允许库存在和发展,而不会在内部发生变化时破坏每个库用户。它被称为应用程序编程接口,而不是应用程序编程类。在较小的规模上,它们还允许多个开发人员在大型项目上成功协作,通过记录良好的接口分隔不同的模块。

抽象类是实现接口时使用的高内聚助手,假设有一定程度的实现细节。或者,抽象类用于定义SPI、服务提供者接口。

API和SPI之间的区别很微妙,但很重要:对于API,重点是谁使用它,而对于SPI,重点是谁实现它。

向API添加方法很容易,API的所有存量用户仍然可以编译。向SPI添加方法很难,因为每个服务提供者(具体实现)都必须实现新方法。如果使用接口来定义SPI,则提供者必须在SPI契约更改时发布新版本。如果使用抽象类,新方法可以根据现有抽象方法定义,或者作为空的throw not implemented exception存根定义,这至少可以允许旧版本的服务实现仍然编译和运行。

关于Java8和默认方法的说明

尽管Java8引入了接口的默认方法,这使得接口和抽象类之间的界限更加模糊,但这并不是为了实现可以重用代码,而是为了更容易地更改既作为API又作为SPI的接口(或者错误地用于定义SPI而不是抽象类)。

用哪一个?

  1. 事情是被代码的其他部分,还是被其他外部代码认为是公开使用?给它添加一个接口,对公共抽象契约隐藏实现细节,这是事情的一般行为。
  2. 事情是不是应该有多个实现,有很多共同的代码?既做一个接口,又做一个抽象的、不完整的实现。
  3. 是不是只有一个实现,没有人会使用它?只要让它成为一个具体类。
    1. “曾经”是很长的时间,你可以安全地玩它,仍然在它上面添加一个界面。

一个推论:反过来经常是错误的:当使用事情时,总是尝试使用你实际需要的最通用的类/接口。换句话说,不要将你的变量声明为ArrayList theList = new ArrayList(),除非你实际上非常依赖它是一个阵列列表,并且没有其他类型的列表适合你。相反,使用List theList = new ArrayList,甚至Collection theCollection = new ArrayList,如果它是一个列表,而不是任何其他类型的集合实际上并不重要。

抽象类是不能创建对象的类或不能实例化的类。抽象方法使类抽象。需要继承抽象类才能覆盖抽象类中声明的方法。对访问说明符没有限制。抽象类中可以有构造函数和其他具体(非abstarct方法)方法,但接口不能有。

接口是方法的蓝图/模板。(例如,给定纸上的房子(接口房子),不同的建筑师将使用他们的想法来构建它(实现房子接口的建筑师类)。它是抽象方法、默认方法、静态方法、最终变量和嵌套类的集合。所有成员都将是最终成员或公共成员,不允许使用受保护和私有访问说明符。不允许创建对象。为了使用实现接口以及覆盖接口中声明的抽象方法,必须创建一个类。接口是松耦合(动态多态/动态绑定)的一个很好的例子接口实现了多态和抽象。它告诉我们该做什么,但如何做是由实现类定义的。有一家汽车公司,它希望它制造的所有汽车的某些功能都是相同的,因此该公司将制造具有这些功能的接口车辆,而不同类别的汽车(如Maruti Suzkhi,Maruti 800)将覆盖这些功能(功能)。

当我们已经有抽象类时,为什么要接口?Java只支持多级和分层继承,但在接口的帮助下,我们可以实现多重继承。

我想再增加一个有意义的区别。

例如,你有一个包含数千行代码的框架,现在如果你想在整个代码中添加一个新特性,最好在抽象类中而不是在接口中添加该方法。因为,如果你在接口中添加这个方法,那么你应该在所有实现的类中实现它,但如果你在抽象类中添加该方法,情况就不同了。

界面:转弯(左转,右转。)

抽象类:轮子。

类:方向盘,源自车轮,暴露界面转弯

一个是对可以在不同范围内提供的行为进行分类,另一个是对事物的本体论进行建模。

简而言之,差异如下:

接口抽象类之间的语法差异:

  1. 抽象类的方法和成员可以具有任何可见性。接口的所有方法都必须是公共//从Java9不再成立
  2. 摘要类的具体子类必须定义所有抽象方法。摘要子类可以有抽象方法。接口扩展另一个接口不需要为从父接口继承的方法提供默认实现。
  3. 一个子类只能扩展一个类。接口可以扩展多个接口。一个类可以实现多个接口。
  4. 子类可以定义具有相同或更少限制性可见性的抽象方法,而实现接口的类必须将所有接口方法定义为public。
  5. 抽象类可以有构造函数,但不能有接口
  6. Java9的接口具有私有静态方法。

现在的界面:

public static-支持
public abstract-支持
public default-支持
private static-支持
private abstract-编译错误
private default-编译错误
private-支持

为了给出一个简单而清晰的答案,它有助于设置上下文:当您不想提供完整的实现时,您可以使用两者。

主要区别在于接口根本没有实现(只有没有主体的方法),而抽象类也可以有带有主体的成员和方法,即可以部分实现。

抽象类和接口之间的区别代表真实实现。

接口:它是一个关键字,用于定义对象的模板或蓝图,它强制所有子类遵循相同的原型,至于实现,所有子类都可以根据需要自由实现功能。

我们应该使用接口的其他一些用例。

两个外部对象之间的通信(我们应用程序中的第三方集成)通过接口完成,这里的接口用作合约。

抽象类:抽象,它是一个关键字,当我们在任何类之前使用这个关键字时,它就变成了抽象类。

抽象类的示例:

 public abstract class DesireCar{
//It is an abstract method that defines the prototype.public abstract void Color();
// It is a default implementation of a Wheel method as all the desire cars have the same no. of wheels.// and hence no need to define this in all the sub classes in this way it saves the code duplicasy
public void Wheel() {
Console.WriteLine("Car has four wheel");}}

**Here is the sub classes:**
public class DesireCar1 : DesireCar{public override void Color(){Console.WriteLine("This is a red color Desire car");}}
public class DesireCar2 : DesireCar{public override void Color(){Console.WriteLine("This is a red white Desire car");}}

界面示例:

  public interface IShape{// Defines the prototype(template)void Draw();}

// All the sub classes follow the same template but implementation can be different.
public class Circle : IShape{public void Draw(){Console.WriteLine("This is a Circle");}}
public class Rectangle : IShape{public void Draw(){Console.WriteLine("This is a Rectangle");}}

你可以发现接口抽象类。之间的明显区别

接口

  • 接口只包含抽象方法。
  • 强制用户在实现接口时实现所有方法。
  • 仅包含最终变量和静态变量。
  • 使用接口关键字声明。
  • 接口的所有方法都必须定义为public。
  • 一个接口可以扩展,或者一个类可以实现多个其他接口。

抽象类

  • 抽象类包含抽象和非抽象方法。

  • 不强制用户在继承时实现所有方法抽象类。

  • 包含所有类型的变量,包括原语和非原语

  • 使用抽象关键字声明。

  • 抽象类的方法和成员可以使用任何可见性。

  • 子类只能扩展单个类(抽象类或具体类)。

如果您有一些可以被多个类使用的通用方法,请选择抽象类。否则,如果你想让类遵循一些明确的蓝图,就去接口。

下面的例子证明了这一点。

Java中的抽象类:

abstract class Animals{// They all love to eat. So let's implement them for everybodyvoid eat(){System.out.println("Eating...");}// The make different sounds. They will provide their own implementation.abstract void sound();} 
class Dog extends Animals{void sound(){System.out.println("Woof Woof");}} 
class Cat extends Animals{void sound(){System.out.println("Meoww");}}

以下是Java中的接口实现:

interface Shape{void display();double area();} 
class Rectangle implements Shape{int length, width;Rectangle(int length, int width){this.length = length;this.width = width;}@Overridepublic void display(){System.out.println("****\n* *\n* *\n****");}@Overridepublic double area(){return (double)(length*width);}} 
class Circle implements Shape{double pi = 3.14;int radius;Circle(int radius){this.radius = radius;}@Overridepublic void display(){System.out.println("O"); // :P}@Overridepublic double area(){return (double)((pi*radius*radius)/2);}}

简而言之,一些重要的关键点:

  1. 在Java接口中声明的变量默认是Final的。抽象类可以有非Final变量。

  2. 在接口中声明Java变量默认是静态的。抽象类可以有非静态变量。

  3. 默认情况下,Java接口的成员是公共的。Java的抽象类可以具有类成员的常见风格,如私有、保护等。

抽象类和接口的一般思想是由使用这些通用“设置”(某种模板)的其他类(不能单独构造)扩展/实现,从而可以简单地为后来扩展它的所有对象设置特定的一般行为。

抽象类有常规方法集和抽象方法。扩展类在被抽象类扩展后可以包含未设置的方法。设置抽象方法时-它们由稍后扩展它的类定义。

接口具有与抽象类相同的属性,但仅包含抽象方法,可以在其他类中实现(并且可以实现多个接口),这创建了方法/静态变量的更永久的固体定义。与抽象类不同,您不能添加自定义“常规”方法。

php.net上抽象类和接口的简单而有效的解释:

接口就像一个协议。它不指定对象的行为;它指定你的代码如何告诉该对象采取行动。接口就像英语语言:定义接口定义了你的代码如何与实现该接口的任何对象通信。

接口总是一个协议或承诺。当一个类说“我实现接口Y”时,它是在说“我承诺拥有与任何具有接口Y的对象相同的公共方法”。

另一方面,抽象类就像一个部分构建的类。它很像一个需要填写空白的文档。它可能使用英语,但这并不像一些文档已经编写好这一事实那么重要。

抽象类是另一个对象的基础。当一个类说“我扩展了抽象类Y”时,它是在说“我使用了另一个名为Y的类中已经定义的一些方法或属性”。

因此,考虑以下PHP:

<?phpclass X implements Y { } // this is saying that "X" agrees to speak language "Y" with your code.
class X extends Y { } // this is saying that "X" is going to complete the partial class "Y".?>

如果您要分发一个供其他人使用的类,您将让您的类实现一个特定的接口。该接口是为您的类拥有一组特定的公共方法的协议。

如果您(或其他人)编写的类已经编写了一些您想在新类中使用的方法,则您的类将扩展一个抽象类。

这些概念虽然容易混淆,但却特别不同和不同。出于所有意图和目的,如果您是任何类的唯一用户,您不需要实现接口。

我们在接口和抽象类之间有各种结构/语法上的差异。更多的差异是

[1]基于情景的差异

抽象类用于限制用户创建父类对象的场景,我们相信将来会添加更多的抽象方法。

当我们确定不能再提供抽象方法时,必须使用接口。然后只发布一个接口。

[2]概念差异

“我们将来需要提供更多的抽象方法吗?”如果是,则使其成为抽象类,如果否,则使其成为接口。

(在Java 1.7之前最合适和有效)

通常抽象类用于某物的核心,而接口用于附加外设。

当你想为车辆创建基本类型时,你应该使用抽象类,但如果你想添加一些不属于车辆基本概念的功能或属性,你应该使用接口,例如你想添加“ToJSON()”函数。

接口具有广泛的抽象而不是抽象类。你可以通过这个例子arguments.look看到这一点:

在此处输入图片描述

如果您使用车辆作为参数,您可以使用其派生类型之一(公共汽车或汽车相同类别只是车辆类别)。但是当你使用IMoveable接口作为参数时,你有更多的选择。

在实用术语(JAVA)中,抽象类和接口之间的主要区别是抽象类可以保持状态。除了保持状态,我们还可以使用Interface实现rest操作。

我迟到了10年,但想尝试任何方式。几天前写了一篇同样的帖子。想把它贴在这里。

tl; dr;当你看到“Is A”关系时,使用继承/抽象类。当你看到“有”关系时,创建成员变量。当你看到“依赖于外部供应商”时,实现(而不是继承)一个接口。

面试问题:接口和抽象类有什么区别?你如何决定何时使用什么?我主要得到以下一个或全部答案:答案1:你不能创建抽象类和接口的对象。

ZK(那是我的首字母缩写):你不能创建两者的对象。所以这不是区别。这是接口和抽象类之间的相似性。计数器问题:为什么不能创建抽象类或接口的对象?

答案2:抽象类可以有一个函数体作为部分/默认实现。

ZK:反问题:所以如果我把它改成一个纯抽象类,把所有的虚函数都标记为抽象的,并且没有为任何虚函数提供默认实现。这会让抽象类和接口变得一样吗?之后它们可以互换使用吗?

答案3:接口允许多继承,抽象类不允许。

ZK:反问:你真的从接口继承吗?还是你只是实现了一个接口,然后从抽象类继承?实现和继承有什么区别?这些反问问题让候选人感到困惑,让大多数人挠头或只是转向下一个问题。这让我认为人们需要帮助掌握面向对象编程的这些基本构建块。原始问题和所有反问题的答案都可以在英语和UML中找到。您必须至少了解以下内容才能更好地理解这两个结构。

常用名词:普通名词是指同一类或同一种类的事物的“共同”名称。例如水果、动物、城市、汽车等。

专有名词:专有名词是指物体、地点或事物的名称。苹果、猫、纽约、本田雅阁等。

Car是一个普通名词,而Honda雅阁是一个专有名词,可能是一个复合专有名词,一个由两个名词组成的专有名词。

来到UML部分。您应该熟悉以下关系:

  • 是一个
  • 有一个
  • 使用

让我们考虑下面的两个句子。本田雅阁是汽车吗?本田雅阁有车吗?

哪一个听起来正确?简单的英语和理解。本田雅阁和汽车有一个“是A”的关系。本田雅阁里面没有车。它“是”一辆车。本田雅阁里面有一个“音乐播放器”。

当两个实体共享“Is A”关系时,它是继承的更好候选者。并且有关系是创建成员变量的更好候选者。有了这个,我们的代码看起来像这样:

abstract class Car{string color;int speed;}class HondaAccord : Car{MusicPlayer musicPlayer;}

现在本田不生产音乐播放器。或者至少这不是他们的主要业务。

所以他们联系了其他公司并签订了一份合同。如果你在这里收到电力,输出信号在这两根电线上,它就会在这些扬声器上播放得很好。

这使得Music Player成为界面的完美候选者。只要连接正常工作,您就不关心谁为其提供支持。

你可以用索尼或其他方式替换LG的MusicPlayer。它不会改变本田雅阁的任何事情。

为什么不能创建抽象类的对象?

因为你不能走进展厅说给我一辆车。你必须提供一个专有名词。什么车?可能是本田雅阁。那时销售代理可以给你买东西。

为什么你不能创建一个接口的对象?因为你不能走进展厅说给我一份音乐播放器的合同。这没有帮助。界面位于消费者和提供商之间,只是为了促进协议。你将如何处理协议的副本?它不会播放音乐。

为什么接口允许多重继承?

接口不被继承。接口被实现。界面是与外部世界交互的候选者。本田雅阁有一个加油接口。它有轮胎充气接口。和用来给足球充气的软管一样。所以新代码如下所示:

abstract class Car{string color;int speed;}class HondaAccord : Car, IInflateAir, IRefueling{MusicPlayer musicPlayer;}

而英文会这样读“本田雅阁是一款支持充气轮胎和加油的汽车”。

抽象类与接口的主题主要是关于语义学的。

抽象类在不同的编程语言中通常作为接口的超集,除了一件事,那就是您可以实现多个接口,但只继承一个类。

接口定义了某物必须能够做的事情;比如合同,但不提供它的实现。

抽象类定义什么东西是,它通常承载子类之间的共享代码。

例如,Formatter应该能够format()某物。描述此类内容的常见语义学是创建一个接口IFormatter,其中声明format(),其行为类似于合同。但是IFormatter并没有描述某物是什么,而是它应该能够做什么。描述某物实际是什么的常见语义学是创建一个类。在这种情况下,我们创建了一个抽象类……所以我们创建了一个抽象类Formatter来实现接口。这是一个非常具描述性的代码,因为我们现在知道我们有一个Formatter,我们现在知道每个Formatter必须能够做什么。

还有一个非常重要的主题是留档(至少对某些人来说…)。在你的留档中,你可能想在你的子类中解释Formatter实际上是什么。在你的子类中有一个抽象类Formatter可以链接到它的留档是非常方便的。这是非常方便和通用的。另一方面,如果你没有抽象类Formatter,只有接口IFormatter,你必须在你的每个子类中解释Formatter实际上是什么,因为接口是一个契约,你不会在接口的留档中描述Formatter实际上是什么——至少这不是常见的事情,你会打破大多数开发人员认为正确的语义学。

注意:使抽象类实现接口是一种非常常见的模式。

所谓接口是因为它为调用者(或例如COM客户端)提供了由某个类实现的方法的接口。通过多态地将对象指针转换为对象类实现的接口的类型,它限制了对象对其实现的接口的函数和成员的访问,与coclass可能实现的其他COM接口分离。客户端不需要知道什么类实现了接口或者类中存在什么其他方法;对象呈现为它知道的接口的实例(其中类的实例已被多态转换为接口实例,接口实例是类的子实例),它只是通过调用接口实例上接口的方法来使用接口。实际实现的所有细节和不同接口实现的无关功能/细节都与调用者期望的接口分开——调用者只使用它与对象(接口实例及其作为对象一部分的虚表指针)的接口,调用底层对象实现,调用者不必知道实现的位置或细节。通过接口(接口类型的指针)访问对象是一种封装形式,在语法上防止对对象的未经授权的访问,以及隐藏实现细节和其他与接口及其定义的个性无关的功能。

接口是所有方法都是虚拟和抽象的(抽象在C++中被称为纯虚拟;所有抽象方法都包含虚拟说明符,因此是虚拟的)。抽象类是至少有一个方法是虚拟的,并被指定为抽象(或C++中的纯虚拟)。其他细节因语言而异。所有接口属性在java中隐式地public static final,但在C++中不是。Java允许抽象类中的非静态属性,但C++允许它们在两者中。属性在两种语言中都不能是虚拟/抽象的。

相似之处
两者都强制类扩展或实现它们以覆盖基方法。

差异

  1. 一个类可以实现多个接口。
  2. 一个类只能从一个抽象类扩展。
  3. 在接口中声明的字段必须是静态最终,因为从这种实现创建的所有对象共享相同的值。
  4. 在抽象类中,字段可以被命名而不被分配。子类可以覆盖它们。

用户名

  1. 抽象类用于密切相关或具有几乎相同功能和行为的子类。
  2. 接口用于您想要强制执行某件事或行为的不相关类,因为它只是一个没有实现的契约。
  1. 抽象类提供声明和实现,但接口只有声明。
  2. 当你想实现多重继承时,你应该使用接口而不是抽象类,因为在C#中,一个类只能从一个类继承,但可以从多个接口继承。
  3. 抽象类包含构造函数,而Interface不包含。
  4. 接口只有公共成员,而抽象类可以包含公共的、私有的受保护修饰符。
  5. 抽象类可以提供完整、部分或不提供实现,而接口只提供声明。
  6. 性能方面,抽象类速度很快,因为Interface需要识别实际的方法实现,这需要一些时间。
  7. 接口为您提供类的功能,而抽象类为您提供类的标识。
  8. 抽象类允许您定义和实现一些可以被许多子类使用的通用功能,但Interface为您提供了可以根据需求以不同方式实现的通用方法签名。
  9. 抽象类可以为任何新添加的方法提供默认实现,并且所有代码都可以正常工作,但对于Interface,您需要在使用该接口的所有类中实现该新方法。
  10. 接口的成员不能是静态的,但抽象类的完整成员可以是静态的。
  11. 接口允许您在单元测试中轻松创建Mocks,而抽象类需要额外的编码。