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


1753

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


96
这是一个非常常见的面试问题。令人惊讶的是,与其他事物相比,抽象类很少在解决方案中使用。您的问题帮助了萨弗拉兹(Safraz)。
卡托2014年

5
这个问题也可能有助于理解接口的概念stackoverflow.com/q/8531292/1055241
gprathour 2014年

6
我已经从该问题中删除了PHP标签,因为几乎没有答案是特定于语言的,而且问题本身也不是特定于语言的。
布莱斯

2
早在c ++中,接口是一个纯抽象基类,所有方法的实现都为0。如果单个方法不是= 0,则它具有一个实现,并且抽象基不再是纯净的,并且不再是接口。我认为当多重继承仅使用纯抽象基数时,VMT的间接性会减少,但我不记得它们的外观已经太长了。
吉姆(Jim

Answers:


2255

介面

接口是一种契约:编写接口的人说:“ 嘿,我接受那样的事情 ”,而使用接口的人说:“ 好,我编写的类看起来就这样 ”。

接口是一个空壳。这些方法只有签名,这意味着这些方法没有主体。该界面无法执行任何操作。这只是一个模式。

例如(伪代码):

// 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模块获得的编程技巧,实际上是在使用元类,因此也使用类。接口与这种语言中的鸭子类型更相关,它是约定和调用描述符的特殊方法(__method__方法)之间的混合。

和编程一样,理论,实践和实践都是另一种语言:-)


6
关于接口的关键点不在于让他们说出类的作用,还在于允许Wizzle的对象使自己对需要Wizzler的代码有用。请注意,在许多情况下,编写可以Wizzle的东西的人或需要Wizzler的人都不会是编写界面的人。
2013年

187
我认为CPU消耗不是接口上值得强调的地方。
丹·拉格

5
@ e-satis能否请您解释一下CPU利用率?为什么抽象类为类会增加CPU使用率?您在这里指的是哪种查询?
极客2014年

36
@ e-satis使用Java 8,您可以在接口中定义默认方法,这等效于在抽象类中使用非抽象方法。有了这一新增功能,除了我应该使用接口这一事实之外,我再也看不到抽象类和接口之间的真正区别,因为类可以实现多个接口,但只能继承一个类
Ogen

23
我想的比较interface,并classHead First Java生动的是A class defines who you are, and an interface tells what roles you could play
LittleLittleQ

872

抽象类接口之间的主要技术区别是:

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

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

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

  • 同样,扩展另一个接口的接口也不负责从父接口实现方法。这是因为接口无法定义任何实现。

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

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


123
我认为这是最好的答案,因为它突出了所有关键差异。一个例子并不是必须的。
约书亚K

4
通常,使用类可以从对象实例化对象,这与CANNOT要实例化的抽象类不同。
SASM 2013年

我认为实现该接口的类需要定义该接口中的所有方法?
Jiazzy用户2013年

@Jiazzyuser如果抽象类实现了接口,则不必实际定义接口的方法。该要求可以推迟到继承/子具体类。但是,具体类必须实现其父类未实现的所有接口方法。我将添加示例来说明这一点。
贾斯汀·约翰逊

5
“继承一个抽象类时,子类必须定义抽象方法,而一个接口可以扩展另一个接口,而不必定义方法。” - 这不是真的。就像接口可以扩展接口而不定义方法一样,抽象类可以继承抽象类而无需定义方法。
尼克

141

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

在此处输入图片说明 摘自:

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


17
您需要说这适用于什么语言(“抽象类不支持多重继承”远非普遍适用)
Ben Voigt 2014年

每个表的最后一个比较令人困惑!接口中的方法不能是静态的,而变量是静态的final抽象类中的已实现方法可以是静态的
realPK 2014年

8
接口的成员必须是static final。最后的陈述是错误的。
Jawad Zeb 2014年

我认为此答案中的“功能”是指“实现”。不确定“行为”是什么意思-也许是“签名”?
LarsH '16

2
这里的目标编程语言是什么?C#?
彼得·莫滕森

80

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

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

接口类似于抽象类。实际上,接口与类和抽象类占用相同的名称空间。因此,您不能定义与类同名的接口。接口是一个完全抽象的类;它的任何方法均未实现,并且据说不是从该方法子类继承而来,而是实现了该接口。

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


4
这是最正确的答案,因为PHP接口与其他语言不同,因为PHP接口是幕后的抽象类,而其他语言的接口是这些类必须匹配的签名。只要没有错误,它们的行为就一样。
Tor Valamo 09年

1
的确,对于PHP来说,这是真正的最佳选择。但是,从文本Blob中获得比从简单片段中获得更困难。
e-satis

从您提供的定义来看,除了一个细节外,它们看起来是相同的:接口是100%抽象的,而抽象类是部分抽象的,可以有一些方法实现(也许所有方法都可以有实现?)。
jww 2014年

41

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

简单来说,我想说:

接口:由多个不相关的对象实施合同

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

从Oracle 文档

如果满足以下条件,请考虑使用抽象类

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

如果满足以下条件,请考虑使用接口

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

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

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

爪哇8具有降低之间的间隙interfaceabstract通过提供一类在一定程度上default的方法的特征。接口没有实现的方法不再有效。

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

请看一下这个SE问题,以获取更好的代码示例。

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


38

一些重要的区别:

以表格的形式:

区别

正如javapapers的Joe所说

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

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

3. Java接口的成员默认情况下是公共的。Java抽象类可以具有类成员的常用风格,例如private,protected等。

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

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

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

7,接口绝对是抽象的,不能实例化;Java抽象类也无法实例化,但是可以在存在main()的情况下调用。

8,与Java抽象类相比,Java接口比较慢,因为它需要额外的间接调用。


3
我已经编辑了您的答案,以提供正确的归因。您不能只是在答案的底部放置一个链接。您还需要引用从其他来源复制的所有语言。另外,如果该表是从某处绘制的,则应明确指出该表的来源。
布拉德·拉尔森

也请提及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 2014年

@MageshBabu也许在包含纯虚函数的类中定义一个函数会使它成为抽象类而不是接口
cbinder

2
使用Java 8,现在的差异变小了。在此处检查更新的差异:journaldev.com/1607/…–
Pankaj

31

要点是:

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

谢谢您,我们现在得到了高水平的回应。有趣的是,您必须深入评论才能找到基于理解的更多响应。
安德鲁(Andrew)

1
其他答案太技术性了。这正朝着我认为是“正确”的答案迈进。OOP的全部要点是语义,这里是否通过CPU昂贵的查找调用私有嵌套类的公共获取器几乎是不相关的
Sentinel

26

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

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


24

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

建筑物的蓝图界面

  • 例如,Servlet(I)

建筑高达200层-部分完成--- 摘要

  • 部分实现,例如,通用和HTTP Servlet

建筑施工完成- 混凝土

  • 完整的实现,例如拥有自己的servlet

接口

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

抽象

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

取自DurgaJobs网站


抽象类可以具有构造函数
vimal krishna

4
我完全不同意这种观点。蓝图与“接口”是完全不同的概念。蓝图更类似于针对特定实现的静态模型或设计规范。它更接近“类”,因为可以通过其构造函数多次实例化该蓝图,但由于“类”还包含有关如何构造(ctor)的规范以及执行方法,因此它甚至还不够接近所以。界面作为一种概念旨在表示某些行为,例如加热/冷却,可以应用于多种事物,例如:建筑物,烤箱等
Sentinel

18

让我们再次解决这个问题:

首先要知道的是1/1和1 * 1的结果相同,但这并不意味着乘法和除法相同。显然,他们之间保持着良好的关系,但是请注意你们俩是不同的。

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

抽象类对于建模类层次结构很有用。在任何要求乍看之下,我们是在什么部分澄清究竟是要建,但我们知道什么来构建。因此,您的抽象类就是您的基类。

接口可用于让其他层次结构或类知道我的能力。当你说我有能力的时候,你必须具备这种能力。接口会将其标记为类必须实施相同的功能。


2
好的答案,但是数学上的隐喻是没有用的,这使我在写这篇评论时浪费了相当多的时间。现在,将其乘以所有其他已阅读此问题的人。
安德鲁(Andrew)

“数学隐喻是无用的”,你为什么这么认为?
Dhananjay

12

实际上,这非常简单。

您可以将接口视为只允许使用抽象方法而没有其他东西的类。

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

抽象类使您既可以声明(使用抽象方法)也可以定义(使用完整方法实现)想要类具有的行为。

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

最后一件事,

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

这意味着已定义行为的继承被限制为每个类只允许一个继承...即,如果您想要一个封装了来自类A,B&C的行为的类,则需要执行以下操作:类A扩展B,类C扩展A ..拥有多个继承的方式有点复杂...

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

因此,实际上Java仅在“声明的行为”(即接口)中支持多重继承,而在定义的行为中仅支持单一继承..除非您按照我描述的方式进行操作...

希望这是有道理的。


11

接口与抽象类的比较是错误的。相反,应该进行另外两个比较:1)接口与类以及2)抽象与最终类

接口与类

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

interface Package {
  String address();
}

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

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

摘要vs决赛

抽象类是一组不完整的对象。它们无法使用,因为它们会遗漏某些零件。例如,我是一个抽象的GPS感知盒-我知道如何检查我在地图上的位置:

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

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

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

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

在大多数语言中,例如Java或C ++,可能只有一个类,既不是抽象也不是final类。这样的类可以被继承并可以实例化。不过,我不认为这完全符合面向对象的范式。

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


9

简而言之,差异如下:

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

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

在现在的接口中:

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


8

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

接口的定义已随时间而改变。您是否认为接口仅具有方法声明,而只是合同?静态最终变量如何?Java 8之后的默认定义如何?

接口是由于具有多重继承的钻石问题而引入Java的而这正是它们实际要做的。

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

请参阅为什么Java仅在要用作合同时在接口中允许静态最终变量?


1
尽管这是一个重要的区别,但这并不是唯一的区别。
Govind Parmar

7

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

抽象类:车轮。

类别:方向盘,从方向盘派生,暴露出接口转弯

一种是对可以跨多种事物提供的行为进行分类,另一种是对事物的本体建模。


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");
    }
}

以下是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);
    }
}

概括地说一些重要的要点:

  1. 在Java接口中声明的变量默认为final。抽象类可以具有非最终变量。

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

  3. 默认情况下,Java接口的成员是公共的。Java抽象类可以具有类成员的常用风格,例如private,protected等。


4

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

接口和抽象类,尽管从技术角度看显然是相似的,但它们的含义和目的却完全不同。

摘要

  1. 接口定义了一些实现将为实现的合同

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

备选摘要

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

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

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

另一方面,列表的高级用户实际上并不关心列表的实际实现方式,因此应该与这些细节隔离。让我们想象一下,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. “ ever”是很长的时间,您可以放心使用它,并且仍然可以在其上添加一个界面。

一个必然的结论:相反的方法常常被错误地完成:在使用事物时,总是尝试使用实际需要的最通用的类​​/接口。换句话说,不要将变量声明为ArrayList theList = new ArrayList(),除非您实际上非常依赖于它是数组列表,并且没有其他类型的列表会为您削减它。使用它List theList = new ArrayList,或者即使Collection theCollection = new ArrayList它是列表,而不是其他任何类型的集合,实际上都没有关系。


4

并不是真正的原始问题的答案,但是一旦您找到了它们之间的区别的答案,您将进入每种情况何时使用的难题: 什么时候使用接口或抽象类?何时同时使用?

我对OOP的了解有限,但是到目前为止,将接口视为语法中的形容词的等效项对我来说一直有效(如果此方法是伪造的,请改正我!)。例如,接口名称就像您可以为类赋予的属性或功能,并且一个类可以具有许多名称:ISerializable,ICountable,IList,ICacheable,IHappy等。


3

继承用于两个目的:

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

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

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

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

有时候,将类型替换为许多不同的东西很有用;在其他情况下,对象将父类型的数据成员和方法实现视为自己的对象很有用。在接口和抽象类之间进行区分可以在最相关的情况下使用每种功能。


3

关键点:

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

优点:

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

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


3

概括起来最简单的方法interface是:

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

同时,一个abstract类是:

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

或者,如果我们要熬了这一切的一句话:一个interface就是实现类,但一abstract类是子类什么


3

我想再加上一个有意义的区别。例如,您有一个包含数千行代码的框架。现在,如果您想使用方法EnhanceUI()在整个代码中添加新功能,则最好在抽象类而不是接口中添加该方法。因为,如果在接口中添加此方法,则应在所有已实现的类中实现该方法,但如果在抽象类中添加该方法则不是这种情况。


3

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

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


由于您刚刚回答了问题,因此您的回答没有考虑defaultJava 8中的关键字,您也可以使用该关键字在接口中定义具体方法。
philantrovert

就像我说的那样,对于处于学习区别中的人来说,这是一个“简单而明确的答案”。对于这样的人来说,知道这种例外并没有任何好处,这只会非常令人困惑。
user3775501

3

代表实际实现的抽象类和接口之间的差异。

接口:它是一个关键字,用于定义对象的模板或方案,并强制所有子类遵循相同的原型,就实现而言,所有子类均可以根据需要自由实现功能这是必需的。

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

通过接口完成两个外部对象之间的通信(在我们的应用程序中为第三方集成)在此处接口充当合同。

抽象类:抽象,它是一个关键字,当我们在任何类之前使用此关键字时,它便成为抽象类。它主要用于我们需要定义模板以及对象的某些默认功能之后,所有子类,这样就消除了多余的代码,并消除了一些可以使用抽象类的用例,例如我们希望其他任何类都不能直接实例化该类的对象,只有派生类可以使用该功能。

抽象类的示例:

 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");
        }
    }

3

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

接口

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

抽象类

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

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

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

  • 声明使用abstract关键字。

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

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


2

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

接口是方法的蓝图/模板(例如,给纸房子(接口房子),而不同的建筑师将使用他们的想法来构建它(实现房屋接口的建筑师类别)。抽象方法,默认方法,静态方法,最终变量和嵌套类。所有成员都将是final或public,protected和private访问指定符。不允许对象创建。实现接口并重写接口中声明的抽象方法接口是松耦合(动态多态/动态绑定)的一个很好的例子。接口实现多态和抽象。实现类。例如一家汽车公司,它希望所有制造的汽车的某些功能都相同,以便该公司将制造具有这些功能的接口汽车,而不同类别的汽车(例如Maruti Suzkhi,Maruti 800)将被覆盖这些功能。

我们已经有了抽象类时为什么要接口?Java仅支持多级继承和层次结构继承,但是借助接口,我们可以实现多重继承。


2

从实用性角度讲,抽象类和接口之间的主要区别是 抽象类可以保持状态。 除了保持状态,我们还可以使用Interface来实现rest操作。


1

在一个接口中,所有方法都必须仅是定义,而不能实现单个方法。

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


1

接口和抽象类之间存在各种结构/语法上的差异。还有更多区别

[1] 基于方案的差异

当我们希望限制用户创建父类的对象并且我们相信将来会添加更多的抽象方法时,可以使用抽象类。

当我们确定没有更多的抽象方法可以使用时,必须使用接口。然后仅发布一个接口。

[2] 概念差异

如果是,则“将来是否需要提供更多抽象方法”,如果否,则将其设置为接口。

(最合适且有效直到java 1.7)


1

通常,Abstract类用于某些事物的核心,但接口用于附加外围设备。

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

接口具有广泛的抽象范围,而不是抽象类。您可以在传递参数时看到这一点。看下面的示例:

在此处输入图片说明

如果将车​​辆用作参数,则只能使用其派生类型之一(公交车或与汽车相同的类别,仅与车辆类别相同)。但是当您使用IMoveable接口作为参数时,您会有更多选择。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.