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

Sar*_*raz 1705 oop abstract-class interface

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

e-s*_*tis 2196

接口

接口是一个契约:编写界面的人说:" 嘿,我接受看起来那样的东西 ",使用界面的人说" 好吧,我写的课看起来那样 ".

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

例如(伪代码):

// 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

实现一个接口消耗很少的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");
    }
}
Run Code Online (Sandbox Code Playgroud)

履行

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

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

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

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

  • 我不认为CPU消耗是接口上值得注意的重点. (179认同)
  • @ e-satisf使用Java 8,您可以在接口中定义默认方法,这相当于在抽象类中使用非抽象方法.有了这个补充,我再也看不到抽象类和接口之间的真正区别,除了我应该使用接口,因为类可以实现多个接口,但只能继承一个类 (34认同)
  • 我认为来自`Head First Java`的`interface`和`class`之间的比较是生动的,`一个类定义了你是谁,一个接口告诉你可以扮演什么角色? (22认同)
  • 关于接口的关键不在于它们说的是类的功能,而是允许Wizzle的对象使自己对需要Wizzler的代码有用.请注意,在许多情况下,编写可以Wizzle的东西的人以及需要Wizzler的人都不会是编写界面的人. (6认同)
  • @ e-satisf您能解释一下您对CPU利用率的看法吗?为什么抽象类是一个类会增加CPU利用率?你指的是什么样的查询? (5认同)
  • @ prototype in Java 8接口上的默认方法是为框架写入的新创建方法设置默认impl,如果您开始只有默认方法,则不了解接口的用途.此外,核心差异在于抽象类可以包含状态,而接口则不包含. (3认同)
  • 在某些动态语言中,如果使用接口,解释器将只检查类是否符合实现.在抽象类中,它将设置整个继承性mecanisme,包括查找Method Resolution Order所需的内容.如果你创建了很多对象,那就是一个开销.不是一点,但根据您的要求,您可能需要考虑它. (2认同)

Jus*_*son 847

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

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

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

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

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

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

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

  • 我认为这是最好的答案,因为它突出了所有关键的差异.一个例子并不是真的有必要. (119认同)
  • "在继承抽象类时,子类必须定义抽象方法,而接口可以扩展另一个接口,并且不必定义方法." - 这不是真的.正如接口可以在不定义方法的情况下扩展接口一样,抽象类可以继承抽象类而无需定义方法. (5认同)
  • 通常使用类可以从中实例化一个对象,这与"CANNOT"实例化的抽象类不同. (4认同)
  • @Jiazzyuser 如果抽象类实现了接口,则它不必实际定义接口的方法。该要求可以推迟到继承/子具体类。但是,具体类必须实现其父类未实现的所有接口方法。我将添加示例来说明这一点。 (2认同)

Viv*_*vek 137

An Interface contains only the definition/signature of functionality, and if we have some common functionality as well as common signatures, then we need to use an abstract class. By using an abstract class, we can provide behavior as well as functionality both in the same time. Another developer inheriting abstract class can use this functionality easily, as they would only need to fill in the blanks.

在此输入图像描述 Taken from:

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

  • 你需要说明这适用于哪种语言("抽象类不支持多重继承"远非普遍真实) (15认同)
  • 接口的成员必须是静态final.最后的陈述是错误的. (7认同)
  • 这里的目标编程语言是什么?C#? (2认同)

Kon*_*man 80

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

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

接口类似于抽象类; 实际上,接口占用与类和抽象类相同的名称空间.因此,您无法定义与类同名的接口.接口是一个完全抽象的类; 没有任何方法被实现,而是从它的类子类,它被称为实现该接口.

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

  • 这是最正确的答案,因为PHP接口与其他语言的不同之处在于PHP接口是抽象类,而其他语言的接口是类必须匹配的签名.只要没有错误,它们的行为相同. (4认同)

Rav*_*abu 39

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

简单来说,我想说:

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

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

来自Oracle 文档

考虑使用抽象类,如果:

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

考虑使用接口:

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

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

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

Java 8 通过提供方法功能在一定程度上缩小了类interfaceabstract类之间的差距default.接口没有方法的实现现在不再有效.

有关更多详细信息,请参阅此文档页面.

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

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


sof*_*e99 38

一些重要的区别:

以表格的形式:

区别

正如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接口很慢,因为它需要额外的间接.

  • 我已编辑您的答案以提供正确的归因.您不能只在答案的底部删除一个链接.您还需要引用从其他来源复制的所有语言.此外,如果该表是从某个地方绘制的,您应该清楚地指出它来自哪里. (3认同)
  • 使用Java 8,现在差异较小.在这里查看更新的差异:http://www.journaldev.com/1607/difference-between-abstract-class-and-interface-in-java (2认同)

小智 30

重点是:

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


小智 25

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

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


Jai*_*der 24

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

建筑的蓝图界面

  • 例如,Servlet(I)

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

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

建筑施工完成 - 混凝土

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

接口

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

抽象

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

取自DurgaJobs网站

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

Dha*_*jay 18

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

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

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

抽象类对于建立类层次结构非常有用.乍一看任何要求,我们都清楚知道要构建什么,但我们知道要构建什么.所以你的抽象类是你的基类.

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

  • 很好的答案,但数学比喻是无用的,让我浪费了大约相当于写这篇评论的时间来阅读它。现在乘以所有其他阅读过这个问题的人。 (2认同)

g00*_*ur3 12

实际上它非常简单.

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

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

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

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

最后一件事,

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

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

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

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

希望这是有道理的.


yeg*_*256 11

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

接口与类

接口是两个对象之间的契约.例如,我是邮差,你是一个提供的套餐.我希望你知道你的送货地址.当有人给我一个包裹时,它必须知道它的送货地址:

interface Package {
  String address();
}
Run Code Online (Sandbox Code Playgroud)

是遵守合同的一组对象.例如,我是"Box"组的一个盒子,我遵守邮递员要求的合同.同时我遵守其他合同:

class Box implements Package, Property {
  @Override
  String address() {
    return "5th Street, New York, NY";
  }
  @Override
  Human owner() {
    // this method is part of another contract
  }
}
Run Code Online (Sandbox Code Playgroud)

摘要与决赛

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

abstract class GpsBox implements Package {
  @Override
  public abstract String address();
  protected Coordinates whereAmI() {
    // connect to GPS and return my current position
  }
}
Run Code Online (Sandbox Code Playgroud)

如果由另一个类继承/扩展,该类可能非常有用.但它本身 - 它没用,因为它不能有物体.抽象类可以构建最终类的元素.

最终类是一组完整的对象,可以使用,但不能修改.他们确切知道如何工作和做什么.例如,我是一个总是进入其构造期间指定的地址的Box:

final class DirectBox implements Package {
  private final String to;
  public DirectBox(String addr) {
    this.to = addr;
  }
  @Override
  public String address() {
    return this.to;
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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


Viv*_*ani 8

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

接口的定义随着时间的推移而发生了变化.你认为一个接口只有方法声明而且只是合同吗?那么静态最终变量以及Java 8之后的默认定义呢?

由于具有多重继承的钻石问题,接口被引入Java ,这就是他们实际打算做的事情.

接口是为了避免多重继承问题而创建的构造,可以包含抽象方法,默认定义和静态最终变量.

请参阅为什么Java只允许接口中的静态最终变量?.


Pri*_*jee 8

简而言之,差异如下:

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

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

现在在Interfaces中:

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


Zia*_*han 8

我迟到了 10 年,但我想尝试任何方式。几天前写了一篇关于同样内容的文章。想到将其发布在这里。

\n\n

太长;博士;当您看到 \xe2\x80\x9cIs A\xe2\x80\x9d 关系时,使用继承/抽象类。当您看到 \xe2\x80\x9chas a\xe2\x80\x9d 关系时创建成员变量。当您看到 \xe2\x80\x9crelies on externalprovider\xe2\x80\x9d 时,实现(而不是继承)一个接口。

\n\n

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

\n\n

ZK(That\xe2\x80\x99是我名字的缩写):你不能创建其中任何一个的对象。所以这没有区别。这是接口和抽象类之间的相似之处。计数器\n问题:为什么\xe2\x80\x99不能创建抽象类或接口的对象?

\n\n

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

\n\n

ZK:反问:所以如果我将其更改为纯抽象类,将所有虚函数标记为抽象,并且不为任何虚函数提供默认实现。这会使抽象类和接口相同吗?之后它们可以互换使用吗?

\n\n

答案3:接口允许多继承和抽象类don\xe2\x80\x99t。

\n\n

ZK:反问:你真的继承了接口吗?或者您只是实现一个接口并从抽象类继承?\xe2\x80\x99 实现和继承之间有什么区别?\n这些反问问题让考生摸不着头脑,或者干脆直接进入下一个问题。这让我认为人们需要有关面向对象编程的这些基本构建块的帮助。\n原始问题和所有反问题的答案都可以在英语和 UML 中找到。\n您必须至少了解以下内容才能理解这些两个结构更好。

\n\n

普通名词:普通名词是对同类或同类事物赋予 \xe2\x80\x9cin common\xe2\x80\x9d 的名称。例如水果、动物、城市、汽车等。

\n\n

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

\n\n

汽车是一个普通名词。本田雅阁是一个专有名词,并且可能是一个复合专有名词,一个使用两个名词组成的专有名词。

\n\n

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

\n\n
    \n
  • 是 A
  • \n
  • 有一个
  • \n
  • 用途
  • \n
\n\n

让\xe2\x80\x99s 考虑下面两个句子。\n- HondaAccord 是一辆汽车吗?\n- HondaAccord 有一辆汽车吗?

\n\n

哪一个听起来正确?简单的英语和理解能力。HondaAccord 和 Cars 共享 \xe2\x80\x9cIs A\xe2\x80\x9d 关系。本田雅阁没有\xe2\x80\x99t里面有车。它\xe2\x80\x9是一辆\xe2\x80\x9d汽车。Honda Accord \xe2\x80\x9chas 里面有一个 \xe2\x80\x9d 音乐播放器。

\n\n

当两个实体共享\xe2\x80\x9c是一个\xe2\x80\x9d关系时,\xe2\x80\x99是更好的继承候选者。Has a 关系是创建成员变量的更好候选者。\n建立此关系后,我们的代码如下所示:

\n\n
abstract class Car\n{\n   string color;\n   int speed;\n}\nclass HondaAccord : Car\n{\n   MusicPlayer musicPlayer;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

于是他们联系其他公司并签订了合同。如果您在这里接收电源并在这两条线上接收输出信号,则它\xe2\x80\x99将在这些扬声器上正常播放。

\n\n

这使得音乐播放器成为界面的完美候选者。只要连接工作正常,您\xe2\x80\x99 并不关心谁为其提供支持。

\n\n

您可以将 LG 的 MusicPlayer 替换为 Sony 或其他方式。它不会改变本田雅阁的任何东西。

\n\n

为什么\xe2\x80\x99不能创建抽象类的对象?

\n\n

因为你不能\xe2\x80\x99走进陈列室并说给我一辆车。你\xe2\x80\x99必须提供一个专有名词。什么车?应该是本田雅阁吧 当销售代理可以为您提供一些东西时\xe2\x80\x99s。

\n\n

为什么\xe2\x80\x99不能创建接口的对象?\n因为你不能\xe2\x80\x99走进陈列室并说给我一份音乐播放器合同。它不会\xe2\x80\x99 帮助。消费者和提供商之间的接口只是为了促进达成协议。您将如何处理协议副本?它不会\xe2\x80\x99 播放音乐。

\n\n

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

\n\n

接口不是继承的。接口已实现。\n接口是与外部世界交互的候选接口。\n本田雅阁有一个加油接口。它具有用于给轮胎充气的接口。以及用于给足球充气的同一软管。所以新代码如下所示:

\n\n
abstract class Car\n{\n    string color;\n    int speed;\n}\nclass HondaAccord : Car, IInflateAir, IRefueling\n{\n    MusicPlayer musicPlayer;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

而英文会这样写\xe2\x80\x9c本田雅阁是一款支持轮胎充气和加油的汽车\xe2\x80\x9d。

\n


azk*_*oki 7

这并不是原始问题的答案,但一旦你找到了它们之间差异的答案,你就会进入何时使用的困境: 何时使用接口或抽象类?何时同时使用两者?

我对 OOP 的了解有限,但到目前为止,将接口视为语法中形容词的等价物对我来说一直有效(如果这个方法是假的,请纠正我!)。例如,接口名称就像您可以赋予类的属性或功能,并且一个类可以拥有其中许多属性或功能:ISerialized、ICountable、IList、ICacheable、IHappy,...


Sen*_*nel 7

界面:转动(向左转,向右转.)

抽象类:轮子.

类别:方向盘,源自轮子,暴露界面转向

一种是对可以在各种各样的事物中提供的行为进行分类,另一种是对事物本体进行建模.


Pra*_*ari 6

如果您有一些可供多个类使用的常用方法,请转到抽象类.否则,如果您希望这些类遵循一些明确的蓝图,请转到接口.

以下示例证明了这一点

Java中的抽象类:

abstract class animals
{
    // They all love to eat. So let's implement them for everybody
    void 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");
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是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;
    }
    @Override
    public void display() 
    {
        System.out.println("****\n* *\n* *\n****"); 
    }
    @Override
    public double area() 
    {
        return (double)(length*width);
    }
} 

class Circle implements Shape 
{
    double pi = 3.14;
    int radius;
    Circle(int radius)
    {
        this.radius = radius;
    }
    @Override
    public void display() 
    {
        System.out.println("O"); // :P
    }
    @Override
    public double area() 
    { 
        return (double)((pi*radius*radius)/2);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  1. Java界面中声明的变量默认为final.抽象类可以包含非最终变量.

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

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


Pra*_*ari 5

关键点:

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

优势:

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

在这里找到详细信息... http://pradeepatkari.wordpress.com/2014/11/20/interface-and-abstract-class-in-c-oops/


Jus*_*ica 5

最简单的总结就是 aninterface是:

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

同时,一个abstract类是:

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

或者,如果我们想将其全部归结为一句话:Aninterface是实现类所拥有的,而类则abstract是子类所拥有的


Ser*_*riu 5

许多初级开发人员错误地将接口、抽象类和具体类视为同一事物的微小变体,并纯粹出于技术原因选择其中之一:我需要多重继承吗?我需要一些地方来放置常用方法吗?除了具体的课程之外,我还需要费心吗?这是错误的,隐藏在这些问题中的是主要问题:“我”。当您为自己编写代码时,您很少会想到其他现在或未来的开发人员正在处理您的代码或使用您的代码。

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

概括

  1. 接口定义了一些实现将为履行的契约

  2. 抽象类提供了一个默认的行为您的实现可以重复使用。

替代摘要

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

论隐藏实现细节的重要性

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

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

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

API 与 SPI

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

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

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

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

关于 Java 8 和默认方法的说明

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

使用哪一种?

  1. 事物是否应该由代码的其他部分或其他外部代码公开使用?给它添加一个接口,对公共抽象契约隐藏实现细节,这是事物的一般行为。
  2. 这个东西应该有多个实现,有很多共同的代码吗?制作一个接口和一个抽象的、不完整的实现。
  3. 会不会只有一种实现,而没有其他人会使用它?把它变成一个具体的类。
    1. “永远”是很长一段时间,你可以安全地玩它,并且仍然在它上面添加一个界面。

一个推论:反过来往往是错误的:在使用thing 时,总是尝试使用您实际需要的最通用的类​​/接口。换句话说,不要将您的变量声明为ArrayList theList = new ArrayList(),除非您实际上非常依赖它是一个数组列表,并且没有其他类型的列表会为您削减它。使用List theList = new ArrayList替代,甚至Collection theCollection = new ArrayList如果一个事实,即它是一个列表,而不是任何其他类型的集合实际上没有问题。


小智 5

您可以找到接口抽象类之间的明显区别

界面

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

抽象类

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

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

  • 包含各种变量,包括原始变量和非原始变量

  • 使用抽象关键字声明。

  • 抽象类的方法和成员可以定义为任何可见性。

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


归档时间:

查看次数:

1233551 次

最近记录:

5 年,9 月 前