根据我的经验,我认为以下内容是正确的。如果我错过了一个要点,请告诉我。
接口:
接口中声明的每个方法都必须在子类中实现。接口中只能存在事件、委托、属性 (C#( 和方法。一个类可以实现多个接口。
抽象类:
只有抽象方法必须由子类实现。抽象类可以具有带有实现的普通方法。抽象类还可以在事件、委托、属性和方法旁边有类变量。一个类只能实现一个抽象类,因为 C# 中不存在多重继承。
因此,即使这种差异也无法解释这个问题。
1(如果你有一个只有抽象方法的抽象类怎么办?这与界面有何不同?
2(如果你在接口中有一个公共变量,它与抽象类有什么不同?
所以任何解释都会有所不同。
除了技术差异之外,主要是您的设计意图应该导致您决定使用其中一个:
接口定义实现它们的类的公共 API。使用接口的目标应该是显示实现它的类的用法。这不是副作用,而是一个中心设计目标,即类可以实现不同的接口来显示它可以扮演的不同角色。
抽象类应该实现一些基本算法或常见行为。它主要是将子类的通用功能连接在一个地方。其目的是定义内部用法或流,而不是公共接口。如果要发布抽象类的用法,它应该实现一个单独的接口。
所以:
1(当您使用上述准则时,只有公共抽象方法的抽象类没有任何意义。抽象类可以定义受保护的抽象方法来定义流或算法。但这在接口上是不可能的。
2(除了公共属性抽象类之外,抽象类可以定义受保护的实例变量,因此有更多的使用场景(见上面的解释(。
编辑:"java"标签已被作者删除。我试图使它尽可能通用,对于java和C#
在Java中:
abstract
class
可以implement
interface
。
interface
不能extend
abstract
class
。
顺便说一句:奇怪的是 - 一个abstract
class
可以在没有实际这样做的情况下implement
和interface
。
interface I {
public String hello ();
}
interface J {
public String goodbye ();
}
abstract class A implements I, J {
@Override
abstract public String hello ();
}
class B extends A {
@Override
public String hello() {
return "Hello";
}
@Override
public String goodbye() {
return "goodbye";
}
}
默认情况下,接口的所有变量都是公共和静态的,接口中不能只有一个公共变量,而在抽象类中,您可以声明一个公共变量。
如果一个类扩展了一个抽象类,它们之间没有任何契约。扩展它的类可能会也可能不会覆盖抽象方法,但是在接口的情况下,接口和实现它的类之间存在严格的契约,即类必须覆盖该接口的所有方法。 因此,从抽象方法的角度来看,它们似乎是相同的,但具有完全不同的属性和优点。
虽然您的问题表明它是针对"通用 OO"的,但它似乎确实侧重于 .NET 使用这些术语。
- 接口可以没有状态或实现 实现接口的
- 类必须提供该接口的所有方法的实现
- 抽象类可能包含状态(数据成员(和/或实现(方法( 抽象类
- 可以在不实现抽象方法的情况下继承(尽管这样的派生类是抽象的( 接口
- 可能是多重继承的,抽象类可能不是(这可能是接口与 abtract 类分开存在的关键具体原因 - 它们允许实现多重继承,从而消除了一般 MI 的许多问题(。
作为一般的OO术语,差异不一定是明确定义的。例如,有C++程序员可能持有类似的严格定义(接口是不能包含实现的抽象类的严格子集(,而有些人可能会说具有一些默认实现的抽象类仍然是一个接口,或者非抽象类仍然可以定义接口。
事实上,有一种称为非虚拟接口 (NVI( 的C++习语,其中公共方法是"扔"到私有虚拟方法的非虚拟方法:
http://www.gotw.ca/publications/mill18.htmhttp://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface
如果你有一个只有抽象方法的抽象类会怎样?如何 这与界面会有所不同吗?
- 您可以实现多个接口,但只能扩展一个类
- 抽象类比接口更不受更改的影响,因为如果您更改接口,它将破坏实现它的类。
- 接口只能有
static final
字段。抽象类可以有任何类型的字段。 - 接口没有构造函数,但抽象类可以有它
但是Java文档是这样说的
如果抽象类仅包含抽象方法声明,则 应改为声明为接口。
即使今天版本的抽象类中的所有方法都是抽象的,该类的未来版本也可以添加虚拟或非虚拟方法,而无需强制修改实现或重新编译消费者。 相比之下,向接口添加任何成员通常需要修改实现接口的所有类以实现该成员,并且无论更改是否添加了尚未实现的任何内容,通常都必须重新编译实现和使用者。
抽象更改可以在不破坏实现或消费者的情况下进行更改,这一事实是有利于抽象类的一大优势。 另一方面,抽象类将强制任何实现类单独派生,而不是从其他类派生。 相比之下,接口几乎会限制其实现者可以继承或派生的内容。 这是有利于接口的一大优势。
因为抽象类和接口都有明确的优势,所以有时任何一个可能比另一个更好。 从概念上讲,可以在接口的工作方式中添加一些功能,使它们具有目前只有抽象类才能享有的优势,但我知道没有特别的计划这样做。
你的类只能扩展一个抽象类,并实现许多接口。
好吧,在抽象类中,你也可以有字段,并且不需要重新实现自动属性。您还可以指定未public
的访问说明符。此外,它具有更好的可扩展性(例如,您可以使用[Obsolete]
来标记旧实现,然后默认情况下使新实现调用旧实现(。此外,它会阻止您再继承类。另一件事是您可以在抽象类中设置静态字段。
此外,接口通常是执行操作的东西,而类则是关于执行操作的东西。
*1) What if you had an Abstract class with only abstract methods? How would that be different from an interface?*
默认情况下,接口中的方法具有"公共抽象",抽象类也将抽象方法作为"公共抽象"。 如果抽象类只包含抽象方法,那么最好使其成为一个接口。
*2) What if you had a Public variable inside the interface, how would that be different than in Abstract Class?*
接口不能有变量。如果您指的是属性、事件、委托等...默认情况下,它们将是"公共"。如果抽象类中未指定任何内容,则为"私有"(仅针对接口/抽象类的成员(。
当您希望类能够执行某些操作时,将使用接口。
当存在'is a'
关系时,您的类将扩展抽象类。
存在语义差异。
在抽象类的情况下。
class Dog : abstractAnimal
当我们创建 Dog 的对象时,我们将不得不创建抽象动物的对象,这将导致额外的对象创建。
在接口的情况下。
class Dog : IAnimal
当我们创建 Dog 的对象时,我们不会创建任何额外的对象。
你可以说:
1(我们可以为类中存在的方法指定不同的访问修饰符, 但是我们无法更改接口成员的访问修饰符。
2(从抽象派生的类不会有强迫 实现。