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


接口和抽象类之间究竟有什么区别?


1473
2017-12-16 08:15


起源


这是一个非常常见的面试问题。令人惊讶的是,与其他事物相比,抽象类在解决方案中很少使用。你的问题帮助了我Safraz。 - Catto
这个问题也可能有助于理解接口的概念 stackoverflow.com/q/8531292/1055241 - gprathour
我已经从这个问题中删除了PHP标签,因为几乎没有一个答案是特定于语言的,而且问题本身并不是特定于语言的。 - brice
你可以阅读博客。你会发现更好的理解。 alpeshsorathiya.blogspot.in/2017/11/... 谢谢。 - Alpesh Sorathiya


答案:


接口

界面是一个 合同:编写界面的人说:“嘿,我接受这样的事情“,使用界面的人说”好吧,我写的课看起来那样”。

接口是一个空壳。只有方法的签名,这意味着方法没有正文。界面无能为力。这只是一种模式。

例如(伪代码):

// I say all motor vehicles should look like this:
interface MotorVehicle
{
    void run();

    int getFuel();
}

// My team mate complies and writes vehicle looking that way
class 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 way
class Car extends MotorVehicle
{
    void run()
    {
        print("Wrroooooooom");
    }
}

履行

虽然抽象类和接口应该是不同的概念,但实现使得该语句有时不真实。有时,它们甚至不是你认为的那样。

在Java中,强制执行此规则,而在PHP中,接口是没有声明方法的抽象类。

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

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


1968
2017-12-16 08:37



关于接口的关键不在于他们说出类的功能,而是允许Wizzle的对象使自己对需要Wizzler的代码有用。请注意,在许多情况下,编写可以Wizzle的东西的人以及需要Wizzler的人都不会是编写界面的人。 - supercat
我不认为CPU消耗是接口上值得注意的重点。 - Dan Lugg
@ e-satisf使用Java 8,您可以在接口中定义默认方法,这相当于在抽象类中使用非抽象方法。有了这个补充,我再也看不到抽象类和接口之间的真正区别,除了我应该使用接口,因为类可以实现多个接口,但只能继承一个类 - Ogen
我想给你一个以上的upvote来解释你... - Ashish Shukla
我认为之间的比较 interface 和 class 从 Head First Java 很生动 A class defines who you are, and an interface tells what roles you could play - AnnabellChan


一个关键的技术差异 抽象类 和 接口 是:

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

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

  • 在继承抽象类时, 具体 儿童班 必须定义抽象方法,而抽象类可以扩展另一个抽象类,而不必定义父类中的抽象方法。

  • 类似地,扩展另一个接口的接口是 不负责实施方法来自父界面。这是因为接口无法定义任何实现。

  • 只有儿童班 扩展单个类 (抽象的或具体的),而接口可以扩展或类可以 实现多个其他接口

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


754
2017-12-16 10:11



我认为这是最好的答案,因为它突出了所有关键的差异。一个例子并不是必需的。 - Joshua K
通常使用类,您可以从中实例化一个对象,而不像抽象类那样 CANNOT 被实例化。 - SASM
我认为实现接口的类需要定义接口中的所有方法? - Jiazzy user
@Jiazzyuser如果抽象类实现了一个接口,它不必实际定义接口的方法。该要求可以推迟到继承/子混凝土类。但是,具体类必须实现其父类未实现的所有接口方法。我将添加示例来说明这一点。 - Justin Johnson
“在继承抽象类时,子类必须定义抽象方法,而接口可以扩展另一个接口,并且不必定义方法。” - 这不是真的。正如接口可以在不定义方法的情况下扩展接口一样,抽象类可以继承抽象类而无需定义方法。 - Nick


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

enter image description here

取自:

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.html http://www.dotnetbull.com/2011/11/what-is-interface-in-c-net.html


110
2017-09-15 08:59



你需要说明这适用于哪种语言(“抽象类不支持多重继承”远非普遍真实) - Ben Voigt
最后的比较是根据表格混淆!接口中的方法不能是静态的,但变量是静态的,最终的抽象类中的实现方法可以是静态的 - realPK
错字它不是Cunstructor ..它的构造函数.. - Pra Jazz
接口成员必须是静态final。最后的陈述是错误的。 - Nepster
这里的目标编程语言是什么? C#? - Peter Mortensen


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

抽象类是一个类   仅由部分实施   程序员。它可能包含一个或多个   抽象方法。一种抽象的方法   只是一个函数定义   用来告诉程序员   方法必须在孩子身上实施   类。

接口类似于抽象   类;确实界面占据了   与类和抽象相同的命名空间   类。出于这个原因,你不能   定义具有相同名称的接口   作为一个班级。界面是完全的   抽象类;没有一种方法   是实现而不是一个类   据说,从中进行分类   实现该接口。

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


77
2017-12-16 08:18



这是最正确的答案,因为PHP接口与其他语言的不同之处在于PHP接口是抽象类,而其他语言的接口是类必须匹配的签名。只要没有错误,它们的行为相同。 - Tor Valamo
没错,对于PHP来说,它是真正最好的anwser。但是从文本blob获取比从简单片段获取更难。 - e-satis
根据您提供的定义,它们看起来相同,除了一个细节:接口是100%抽象,而抽象类是部分抽象的,可以有一些方法实现(也许所有方法都可以实现?)。 - jww


一些重要的差异:

以表格的形式:

Difference

来自javapapers的Joe说

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

2.在Java接口中声明的变量默认为final。抽象类可能包含非最终变量。

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

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

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

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

7.Interface是绝对抽象的,无法实例化; Java抽象类也无法实例化,但如果是,则可以调用   main()存在。

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


37
2018-05-16 05:55



我已编辑您的答案以提供正确的归因。您不能只在答案的底部删除一个链接。您还需要引用从其他来源复制的所有语言。此外,如果该表是从某个地方绘制的,您应该清楚地指出它来自哪里。 - Brad Larson♦
请注意C ++,虽然C ++中没有关键字“interface”,但它也是一个常见的Qn regd C ++。 - cbinder
@cbinder:c ++中没有关键字'interface'。有关c ++的不同之处,请参阅1。 tutorialspoint.com/cplusplus/cpp_interfaces.htm 2。 tutorialspoint.com/cplusplus/cpp_interfaces.htm - softmage99
@MageshBabu也许在包含纯虚函数的类中定义一个函数使它成为一个抽象类而不是接口 - cbinder
使用Java 8,现在差异较小。检查更新的差异: journaldev.com/1607/... - Pankaj


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

简单来说,我想说:

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

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

来自Oracle 文件

考虑使用抽象类 如果:

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

考虑使用接口 如果:

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

抽象类与具体类建立“是一种”关系。 interface为类提供“具有”功能。

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

Java 8缩小了差距 interface 和 abstract 通过提供一定程度的课程 default 方法特征。 接口没有方法的实现 现在不再有效了。

请参阅此文档  更多细节。

看看这个SE问题,以便更好地理解代码示例。

我该如何解释Interface和Abstract类之间的区别?


35
2017-11-27 12:42





重点是:

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

23
2017-09-29 09:54



谢谢你,现在我们得到了一个很好的高水平响应的地方。有趣的是,您必须在评论中深入了解更多基于理解的回复。 - Andrew
其他答案太技术性了。这是我认为是'正确'的答案。 OOP的重点是语义,并且通过CPU昂贵的查找调用私有嵌套类公共getter是非常相关的 - Sentinel


如果要在继承层次结构中提供多态行为,请使用抽象类。

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


21
2018-05-28 04:42



现在谷歌多态 - Andrew


我正在建造一个300层的建筑

建筑的蓝图 接口

  • 例如,Servlet(I)

建筑物最多可容纳200层 - 部分完工---抽象

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

建筑工程竣工 - 具体

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

接口

  • 我们对实施,只是要求一无所知。我们可以 去寻找一个界面。
  • 默认情况下,每个方法都是public和abstract
  • 它是一个100%纯粹的抽象类
  • 如果我们宣布公开,我们就不能声明私有和受保护
  • 如果我们声明抽象,我们不能声明final,static,synchronized,strictfp和native
  • 每个界面都有public,static和final
  • 序列化和瞬态不适用,因为我们无法在接口中创建实例
  • 非挥发性因为它是最终的
  • 每个变量都是静态的
  • 当我们在接口内声明一个变量时,我们需要在声明时初始化变量
  • 不允许实例和静态块

抽象

  • 部分实施
  • 它有一个抽象的方法。另外,它使用混凝土
  • 对抽象类方法修饰符没有限制
  • 对抽象类变量修饰符没有限制
  • 我们不能声明除抽象之外的其他修饰符
  • 初始化变量没有限制

取自DurgaJobs网站


21
2017-07-09 18:00



抽象类可以有一个构造函数 - vimal krishna
我完全不同意这种观点。蓝图与“界面”完全不同。蓝图更类似于特定实现的静态模型或设计规范。它更接近'class',因为蓝图可以通过它的构造函数多次实例化,但即使这个也不够接近,因为'class'也包含如何构造(ctor)的规范,以及做法所以。作为概念的界面旨在表示某些行为,例如加热/冷却,可应用于一系列事物,例如:建筑物,烤箱等 - Sentinel


让我们再次讨论这个问题:

让你知道的第一件事是1/1和1 * 1会产生相同的结果,但这并不意味着乘法和除法是相同的。显然,他们保持着良好的关系,但请注意,两者都是不同的。

我将指出主要的不同之处,其余的已经解释过了:

抽象类对于类层次结构的建模很有用。乍一看任何要求,我们都清楚地知道了什么 究竟 是要建造,但我们知道 要建造什么。 所以你的抽象类是你的基类。

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


18
2018-04-11 05:18



很好的答案,但数学比喻是无用的,并且让我浪费大约相当于读写评论的时间。现在,将所有已阅读此问题的其他人相乘。 - Andrew
“数学比喻是无用的”,你为什么这么认为? - Dhananjay


实际上它非常简单。

您可以将接口视为一个类,只允许使用抽象方法而不允许其他方法。

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

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

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

最后一件事,

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

这意味着定义行为的继承被限制为仅允许每个类一个...即,如果您想要一个封装类A,B和C行为的类,您需要执行以下操作:A类扩展B,C类扩展A ..它有点关于多重继承的方式......

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

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

希望这是有道理的。


12
2017-07-22 23:36