我最近接受了两次电话采访,被问及接口类和抽象类之间的区别。我已经解释了我能想到的每一个方面,但似乎他们在等我提一些具体的事情,我不知道是什么。

根据我的经验,我认为以下是正确的。如果我遗漏了一个要点,请告诉我。

接口:

接口中声明的每个方法都必须在子类中实现。接口中只能存在事件、委托、财产(C#)和方法。一个类可以实现多个接口。

抽象类:

子类只能实现抽象方法。抽象类可以具有具有实现的普通方法。除了事件、委托、财产和方法之外,抽象类还可以有类变量。由于C#中不存在多重继承,一个类只能实现一个抽象类。

在这之后,面试官提出了一个问题:“如果你有一个只有抽象方法的抽象类呢?这和接口有什么不同?”我不知道答案,但我认为这是上面提到的继承,对吧?另一位面试官问我,“如果你在接口中有一个公共变量,那会和抽象类中有什么不同?”我坚持认为你不能在接口中使用公共变量。我不知道他想听什么,但他也不满意。

另请参阅:

何时使用接口而不是抽象类,反之亦然接口与抽象类如何决定使用抽象类和接口?接口和抽象类之间的区别是什么?


当前回答

After all that, the interviewer came up with the question "What if you had an 
Abstract class with only abstract methods? How would that be different
from an interface?" 

文档明确指出,如果抽象类只包含抽象方法声明,则应将其声明为接口。

An another interviewer asked me what if you had a Public variable inside
the interface, how would that be different than in Abstract Class?

默认情况下,接口中的变量是公共静态变量和最终变量。问题的框架可以是,如果抽象类中的所有变量都是公共的呢?与接口中的变量不同,它们仍然可以是非静态和非最终的。

最后,我想对上面提到的内容再补充一点——抽象类仍然是类,属于单个继承树,而接口可以存在于多个继承中。

其他回答

从我的另一个答案来看,主要是关于何时使用一个而不是另一个:

根据我的经验,界面是最好的有几个类时使用每个都需要对相同的方法,以便可由其他代码互换使用将针对这些类的公共接口。最好的当协议很重要,但底层逻辑可能不同于每个类别。如果你不是复制逻辑,考虑抽象类或标准类继承相反

从编码角度

如果抽象类只有抽象方法,则接口可以替换抽象类。否则,将抽象类更改为接口意味着您将失去继承提供的代码重用性。

从设计角度

如果它是“Is a”关系,并且您需要一个子集或所有功能,请将其保留为抽象类。如果是“应该做”的关系,请将其保留为界面。

决定你需要什么:只是策略执行,或者代码重用和策略。

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

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

ZK(这是我的首字母缩写):你不能创建任何一个对象。所以这并不是什么区别。这是接口和抽象类之间的相似之处。反问:为什么不能创建抽象类或接口的对象?

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

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

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

ZK:反问:你真的从接口继承吗?还是只实现一个接口,从抽象类继承?实现和继承之间有什么区别?这些反问题会让考生们措手不及,让大多数人挠头,或者直接进入下一个问题。这让我觉得人们需要帮助来构建面向对象编程的基本构件。原始问题和所有反问题的答案都可以在英语和UML中找到。为了更好地理解这两个结构,您必须至少了解以下内容。

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

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

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

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

是A有A使用

让我们考虑以下两句话。-本田雅阁是一辆车?-本田雅阁有车吗?

哪一个听起来正确?简单的英语和理解能力。本田雅阁(HondaAccord)和汽车(Cars)有着“是A”的关系。本田雅阁(Honda accord)没有车,它“是”一辆车。本田雅阁“有一个”音乐播放器。

当两个实体共享“Is A”关系时,它更适合继承。Has a relationship是创建成员变量的更好候选。这样,我们的代码如下所示:

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

英文的意思是“本田雅阁是一款支持轮胎充气和加油的汽车”。

1) 接口可以被视为纯抽象类,这是相同的,但尽管如此,实现接口和从抽象类继承并不相同。当你从这个纯抽象类继承时,你定义了一个层次结构->继承,如果你实现了你不需要的接口,你可以实现任意多的接口,但是你只能从一个类继承。

2) 您可以在接口中定义属性,因此实现该接口的类必须具有该属性。

例如:

  public interface IVariable
  {
      string name {get; set;}
  }

实现该接口的类必须具有这样的属性。

接口:-==合约。无论哪个类实现它都必须遵循接口的所有规范。

一个实时的例子是任何ISO标记的产品。ISO给出了一套规则/规范,说明产品应该如何构建以及它必须具备的最小功能集。

这只是产品必须具备的财产的子集。SO只有在产品满足其标准时才会签署产品。

现在看看这个代码

public interface IClock{       //defines a minimum set of specification which a clock should have

    public abstract Date getTime();
    public abstract int getDate();
}
public class Fasttrack: Clock {
    // Must have getTime() and getTime() as it implements IClock
    // It also can have other set of feature like 
    public void startBackgroundLight() {
        // watch with internal light in it.
    }
    .... //Fastrack can support other feature as well
    ....
    ....
}

在这里,Fastrack被称为手表,因为它具有手表必须具备的所有功能(最小功能集)。

原因和时间摘要:

来自MSDN:

抽象类的目的是提供多个派生类可以共享的基类的公共定义。

例如,类库可以定义一个抽象类,该抽象类用作其许多函数的参数,并要求使用该库的程序员通过创建派生类来提供自己的类实现。抽象只是指如果你不能定义它,就将它完全声明为抽象。实现类将完成这个实现。

例如:假设我声明一个类配方是抽象的,但我不知道该是哪个配方然后我将推广这个类来定义任何菜谱的通用定义。菜谱的植入将取决于菜品的实现。

抽象类既可以由抽象方法组成,也可以由非抽象方法组成。因此,您可以注意到接口中的差异。因此,实现类不一定必须具有每个方法。您只需要重写抽象方法。

简单来说,如果您想要紧密耦合,请使用接口o/w,以防失去耦合抽象类