如果你有一个只有抽象方法的抽象类怎么办?这与界面有何不同?
Posted
技术标签:
【中文标题】如果你有一个只有抽象方法的抽象类怎么办?这与界面有何不同?【英文标题】:What if you had an Abstract class with only abstract methods? How would that be different from an interface? 【发布时间】:2013-07-22 13:00:14 【问题描述】:根据我的经验,我认为以下是正确的。如果我遗漏了一个重点,请告诉我。
界面:
接口中声明的每个方法都必须在子类中实现。接口中只能存在事件、委托、属性 (C#) 和方法。一个类可以实现多个接口。
抽象类:
只有抽象方法必须由子类实现。抽象类可以具有带有实现的普通方法。除了事件、委托、属性和方法之外,抽象类还可以具有类变量。由于C#中不存在多重继承,一个类只能实现一个抽象类。
所以即使是这种差异也不能解释问题
1)
2) 如果接口中有一个公共变量,那与抽象类有什么不同?
所以任何解释都会有不同的帮助。
【问题讨论】:
不知道你说的两个是什么意思。 抽象类中可以有受保护的抽象方法 【参考方案1】:除了技术差异之外,主要是您的设计意图导致您决定使用其中一个:
接口定义实现它们的类的公共 API。您使用接口的目标应该是显示实现它的类的用法。一个类可以实现不同的接口以显示它可以扮演的不同角色,这不是副作用,而是一个中心设计目标。
抽象类应该实现一些基本算法或常见行为。主要是将子类的通用功能加入到一个地方。它的目的是定义内部使用或流程,而不是公共接口。如果你想发布一个抽象类的用法,它应该实现一个单独的接口。
所以:
1) 当您使用上述指南时,只有 public 抽象方法的抽象类没有任何意义。抽象类可以定义 protected 抽象方法来定义流程或算法。但这对于接口是不可能的。
2) 除了公共属性之外,抽象类可以定义受保护的实例变量,因此有更多的使用场景(见上面的解释)。
编辑:作者删除了“java”标签。我试图让它尽可能通用,它应该适用于 java 和 C#
【讨论】:
作者删除了“java”标签。我试图让它尽可能通用,它应该适用于 java 和 C#【参考方案2】:在 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";
【讨论】:
【参考方案3】:默认情况下,接口的所有变量都是公共的和静态的,接口中不能有唯一的公共变量,而在抽象类中可以声明公共变量。
如果一个类扩展了一个抽象类,那么它们之间就没有任何契约。扩展它的类可能会或可能不会覆盖抽象方法,但是在接口的情况下,接口和实现它的类之间有严格的约定,即该类必须覆盖该接口的所有方法。因此,从抽象方法的角度来看,它们看起来是相同的,但具有完全不同的特性和优势。
【讨论】:
它们之间的“契约”被称为里氏替换原则,是好的OO设计最基本的原则之一。这基本上说如果B
继承自A
,那么B
是 一个A
,并且有责任维护所有可证明的关于A
s 的属性。
接口的所有方法都不需要实现。可以把类抽象化,部分实现接口
同意,但是具体的类呢?
在 Java 中,你说的是不可能的:一个具体的类必须实现 all 抽象方法。在 C# 中是否可以不从继承的抽象类中实现抽象方法,使其“空”?这样做有什么意义?您的具体类的用户依赖于您继承的类授予的功能。【参考方案4】:
虽然您的问题表明它是针对“一般 OO”的,但它似乎确实侧重于 .NET 对这些术语的使用。
接口可以没有状态或实现 实现接口的类必须提供该接口所有方法的实现 抽象类可能包含状态(数据成员)和/或实现(方法) 可以在不实现抽象方法的情况下继承抽象类(尽管这样的派生类是抽象的) 接口可能是多重继承的,抽象类可能不是(这可能是接口与抽象类分开存在的关键具体原因——它们允许实现多重继承,从而消除了一般 MI 的许多问题)。作为一般的 OO 术语,差异不一定是明确定义的。例如,有些 C++ 程序员可能持有类似的严格定义(接口是抽象类的严格子集,不能包含实现),而有些人可能会说具有某些默认实现的抽象类仍然是接口或非抽象类仍然可以定义接口。
确实,有一个称为非虚拟接口 (NVI) 的 C++ 习惯用法,其中公共方法是非虚拟方法,它们“转换”到私有虚拟方法:
http://www.gotw.ca/publications/mill18.htm http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface
【讨论】:
这个答案重申了OP对问题的原始知识,完全忽略了实际问题。【参考方案5】:您可以实现多个接口,但只能扩展一个类 抽象类比接口更免疫,因为如果您更改接口,它会破坏实现它的类。 接口只能有如果你有一个只有抽象方法的抽象类怎么办?如何 那会和界面不同吗?
static final
字段。抽象类可以有任何类型的字段。
接口没有构造函数,但抽象类可以有
但是javadocs这样说
如果一个抽象类只包含抽象方法声明,它 应该声明为接口。
【讨论】:
通用 OO 指南适用于每种 OO 语言,并且大多数技术规范是相同的。 @Anirudh 的简短引用(尽管它的源代码)与语言无关,也适用于 C#。【参考方案6】:即使今天版本的抽象类中的所有方法都是抽象的,未来版本的类也可以添加虚拟或非虚拟方法,而无需强制修改实现或重新编译使用者。相比之下,向接口添加任何成员通常需要修改实现该接口的所有类以实现该成员,并且无论更改是否添加了尚未实现的任何内容,实现和消费者通常都必须重新编译。
可以在不破坏实现或消费者的情况下更改抽象更改这一事实是有利于抽象类的一大优势。另一方面,抽象类将强制任何实现类单独从它派生,而不是从其他类派生。相比之下,接口几乎会限制其实现者可以继承或派生的内容。这是有利于接口的一大优势。
因为抽象类和接口各有优势,所以有时两者都可能比另一个更好。从概念上讲,可以在接口的工作方式中添加一些特性,从而赋予它们目前只有抽象类才能享有的优势,但我知道没有具体计划这样做。
【讨论】:
【参考方案7】:您的类只能扩展一个抽象类并实现多个接口。
【讨论】:
【参考方案8】:嗯,在抽象类中,您也可以有字段,并且不需要重新实现自动属性。您还可以指定不是public
的访问说明符。此外,它具有更好的可扩展性(例如,您可以使用[Obsolete]
标记旧实现,然后默认使新实现调用旧实现)。此外,它会阻止您拥有更多的类继承。另一件事是您可以在抽象类中设置静态字段。
此外,接口通常是执行一个动作的东西,而类则是关于成为那个动作。
【讨论】:
你的意思是“让旧的默认调用新的”,不是吗?反之则毫无意义。 @MarcvonRenteln 不,如果没有实施,它就会退回到旧的。【参考方案9】:*1) What if you had an Abstract class with only abstract methods? How would that be different from an interface?*
默认情况下,接口中的方法是“public abstract”,抽象类也将具有抽象方法作为“public abstract”。 如果抽象类只包含抽象方法,那么最好将其设为接口。
*2) What if you had a Public variable inside the interface, how would that be different than in Abstract Class?*
接口不能有变量。如果您的意思是属性、事件、委托等……它们将默认为“公共”。如果抽象类中没有指定任何内容,则它将是“私有”(仅针对接口/抽象类的成员)。
【讨论】:
【参考方案10】:当你希望你的类能够做某事时使用接口。
当存在'is a'
关系时,您的类扩展了一个抽象类。
存在语义差异。
【讨论】:
【参考方案11】:在抽象类的情况下。
class Dog : abstractAnimal
当我们创建 Dog 的对象时,我们将不得不创建 abstractAnimal 的对象,这会导致创建额外的对象。
在接口的情况下。
class Dog : IAnimal
当我们创建 Dog 的对象时,我们不会创建任何额外的对象。
【讨论】:
【参考方案12】:在这种情况下,你可以说:
1) 我们可以为类中存在的方法指定不同的访问修饰符, 但是我们不能改变接口成员的访问修饰符。
2) 从抽象派生的类不会强制 执行。
【讨论】:
以上是关于如果你有一个只有抽象方法的抽象类怎么办?这与界面有何不同?的主要内容,如果未能解决你的问题,请参考以下文章