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

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

接口:

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

抽象类:

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

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

另请参阅:

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


当前回答

我认为他们正在寻找的答案是根本的或OPPS的哲学差异。

当派生类共享抽象类的核心财产和行为时,使用抽象类继承。实际定义类的行为类型。

另一方面,当类共享外围行为时使用接口继承,这些行为不一定定义派生类。

例如,汽车和卡车共享汽车抽象类的许多核心财产和行为,但它们也共享一些外围行为,如生成排气,即使是像司钻或发电机这样的非汽车类也共享,并不一定定义汽车或卡车,因此汽车、卡车、司钻和发电机都可以共享同一个接口IExhaust。

其他回答

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

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

例如:

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

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

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?

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

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

还有一些其他的区别-

接口不能有任何具体的实现。抽象基类可以。这允许您在那里提供具体的实现。这可以允许抽象基类实际上提供更严格的契约,而接口实际上只描述如何使用类。(抽象基类可以具有定义行为的非虚拟成员,这给了基类作者更多的控制权。)

一个类上可以实现多个接口。类只能从单个抽象基类派生。这允许使用接口的多态层次结构,但不允许抽象基类。这也允许使用接口进行伪多重继承。

抽象基类可以在v2+中修改,而不破坏API。对接口的更改正在破坏更改。

[C#/.NET特定]接口与抽象基类不同,可以应用于值类型(结构)。结构不能从抽象基类继承。这允许将行为契约/使用指南应用于价值类型。

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

一个实时的例子是任何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,以防失去耦合抽象类

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

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