根据我的经验,我认为以下几点是真的。如果我缺少要点,请告诉我。
接口:
接口中声明的每个方法都必须在子类中实现。
接口中只能存在事件,委托,属性(C#)和方法。一个类可以实现多个接口。
Abstract类:
只有子类必须实现Abstract方法。 Abstract类可以具有实现的常规方法。抽象类在事件,委托,属性和方法旁边也可以具有类变量。由于C#中不存在多重继承,一个类只能实现一个抽象类。
毕竟,面试官提出了一个问题:“如果您有一个抽象,该怎么办?类只包含抽象方法?与接口有什么不同?”我不知道答案,但我想这就是上面提到的继承?
另一个面试官问我,如果接口内有Public变量,那和Abstract Class有什么不同?我坚持认为,接口内不能有公共变量。我不知道他想听什么,但他也不满意。
另请参见:
何时使用界面而不是
抽象类,反之亦然
接口与抽象类
如何决定使用抽象类和接口?
接口和抽象类有什么区别?
#1 楼
虽然您的问题表明它是针对“通用OO”的,但实际上它似乎主要集中于.NET对这些术语的使用。在.NET(与Java类似)中:
接口不能有状态或实现
实现接口的类必须提供该接口的所有方法的实现
抽象类可能包含状态(数据成员)和/或实现(方法)
抽象类可以在不实现抽象方法的情况下被继承(尽管这样的派生类本身就是抽象的)
接口可能是多继承的,抽象类可能不是(这可能是导致这种情况的关键原因接口与抽象类分开存在-接口允许实现多重继承,从而消除了通用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
评论
谢谢。我认为,既然您的回答提到了状态+所有休息的简要概述,我将您的回答标记为最终答案。您是对的,因为我的第一位面试官要求进行一般OO,所以我要求进行一般的OO,但是由于我是C#人员,所以我往往会忘记这一点。 ;-)同时感谢C ++的解释,因为c ++总是令人不寒而栗。
–侯曼
09年4月17日在17:34
我认为Michael提供的解释中的关键点是,在实现接口时,必须实现接口中的所有成员,但是当从抽象类继承时,子类不需要实现它的父级成员
–吉列尔莫·戈麦斯(Guillermo Gomez)
2010年3月2日在21:12
+1:我愿意打赌,主持采访的那些猴子甚至没有意识到其他语言在OO上的实现方式也不同。
–轨道轻度竞赛
2012年1月11日上午10:49
@JL我看不出问题出在哪里。您似乎将抽象方法与抽象类混淆了。抽象方法没有实现。但是,在抽象类内部,某些方法可以是抽象的(即没有实现),而其他一些方法实际上可以具有实现。
– xji
2014年4月30日4:05
请注意,在Java 8中,您现在可以在接口中具有默认方法和静态方法,这意味着Java接口可以具有实现。参考这里。显然,您主要是指.NET,所以这只是对Java的观察。
–davtom
2014年7月1日13:24
#2 楼
打个比方:当我在空军时,我参加了飞行员培训,成为了美国空军的飞行员。那时我没有资格飞行任何东西,不得不参加飞机型号培训。合格后,我将成为飞行员(抽象班)和C-141飞行员(混凝土班)。在我的一项任务中,我被赋予了额外的职责:安全员。现在,我仍然是飞行员和C-141飞行员,但是我也履行了安全主任的职责(可以说我实施了ISafetyOfficer)。不需要飞行员担任安全官员,其他人也可以做到。所有USAF飞行员都必须遵守某些空军范围的法规,以及所有C-141(或F -16或T-38)飞行员是“美国空军”飞行员。任何人都可以成为安全员。因此,总结一下:
飞行员:抽象类
C-141飞行员:具体类
ISafety Officer:界面
添加了说明:这只是一个类比来帮助解释该概念,而不是编码建议。请参阅下面的各种评论,讨论很有趣。
评论
我真的很喜欢这个比喻,它使用一个简单的示例来解释一个稍微复杂的主题
–凯文·鲍尔索克斯(Kevin Bowersox)
2012年1月7日在16:37
这是了解复杂的OO术语的最佳方法。简而言之,只有在您可以实际使用它时,所有理论才有价值。 @Jay you rexample确实很容易掌握,然后有几个要点(主要是渗透性的思想而不是被吸收的!)
–v s
2012-09-20 8:56
我还是有点困惑。假设您现在获得了F-16和T-38资格,所以Jay班级现在不能继承多个班级(C-141飞行员,F-16飞行员和T-38飞行员),这意味着他们的班级应该成为接口?谢谢
– Alex Okrushko
2013年1月30日15:31
许多人正确地对Alex的评论加了+1,因为这显示了此示例中的某些缺点。首先,我想说周杰伦将是C-141Pilot的一个实例,而不是它自己的类。另外,由于在美国空军中,有99%的飞行员一次只能在一架飞机上合格(FCF和测试飞行员是例外),所以我没有考虑多重资格以及如何实施。据我所知,一名50年前同时拥有25架不同飞机资格的飞行员,我认为这是我们不想使用多重继承的例证。
–杰伊
13年7月16日在5:51
由于一个飞行员不可能一次飞行一架以上的飞机,因此这将是实施该战略模式的好机会。飞行员将拥有一组证书,并在运行时选择正确的证书。认证将被编码为使用TakeOff,Land和Eject方法实现IFlyPlane接口的行为。
–迈克尔·布莱克本
2013年12月22日6:25
#3 楼
我认为他们正在寻找的答案是基本的或OPPS的哲学差异。当派生类共享抽象类的核心属性和行为时,将使用抽象类继承。
另一方面,当类共享外围行为(不一定定义派生类的行为)时,使用接口继承。 >例如汽车和卡车具有许多汽车抽象类的核心属性和行为,但是它们还共享一些外围行为,例如“生成排气”,甚至是非汽车类(例如Drillers或PowerGenerators)也具有这种特性,并且不一定定义汽车或卡车,因此汽车,卡车,司钻和PowerGenerator都可以共享同一接口IExhaust。
评论
我认为一个更好的类比是“ usesFuel”,它可以显示接口的契约性质。
–Pureferret
2012年9月4日在12:15
@Pureferret如果加速是汽车抽象类的核心行为的一部分,那么我不能说加速表明了合同的性质。合同性质是什么?为什么每当我们谈论接口时都会引入这个词合同?
–过度兑换
2014年11月11日18:44
@overexchange,因为通常接口仅是两个“表面”相遇的地方,但是“合同”一词暗示着两个“表面”如何相遇的共识。 (至少对我而言)产生废气是您“同意”的事情,这没有任何意义。但是(再次对我而言),您可以同意需要使用燃料是有道理的。
–Pureferret
2014年11月12日13:27
@Pureferret我在链接上提出了相同的查询
–过度兑换
2014年11月13日在7:28
@Pureferret如果接口需要具有外围行为,那么为什么公共接口List
–过度兑换
2014年11月13日15:51
#4 楼
简短说明:抽象类用于对外观相似的类的类层次结构进行建模(例如Animal可以是抽象类,而Human,Lion,Tiger可以是具体派生类)AND
接口用于2个相似/不相似类之间的通信,这些类不关心实现Interface的类的类型(例如,Height可以是interface属性,可以由Human,Building,Tree来实现。可以吃东西,可以游泳,可以死,也可以做其他任何事情。.这仅是一件需要高度的事情(在课堂上实施)。
评论
我真的很喜欢这个答案,因为有时候很难通过观察更抽象的东西(例如意图)而不是仅仅通过结构来回答事物之间的“区别”(因为在结构上,接口和纯抽象类几乎是相同的事情)。
–LostSalad
14年8月19日在16:09
枚举抽象类与接口在特定语言中可以做什么很容易,但是创建一个抽象以赋予对象以含义和责任则更加困难,并且您所说的完全恢复了OO中使用2概念。谢谢!
–塞缪尔
17-4-17在23:59
@dhananjay:我知道身高可以与动物类的概念区分开,也可以与另一个不同的类分开,但是,类之间的“交流”到底是什么意思?只是为自己的班级定义了高度,对吗?
– T.T.T.
18年2月12日在19:59
#5 楼
还有其他一些区别-接口不能有任何具体的实现。抽象基类可以。这使您可以在那里提供具体的实现。这可以允许抽象基类实际上提供更严格的约定,而接口实际上仅描述了类的使用方式。 (抽象基类可以具有定义行为的非虚拟成员,这可以给基类作者更多的控制权。)
在一个类上可以实现多个接口。一个类只能从单个抽象基类派生。这允许使用接口而不是抽象基类的多态层次结构。这也允许使用接口进行伪多重继承。
可以在v2 +中修改抽象基类而不会破坏API。接口的更改是重大更改。
[C#/。NET特定]接口与抽象基类不同,可以将其应用于值类型(结构)。结构不能从抽象基类继承。这允许将行为合同/使用准则应用于值类型。
评论
+1表示一个类可以实现多个接口的关键点。
–cgp
09年4月17日在16:50
这是接口相对于抽象基类IMO的真正优势。否则,我同意.NET设计指南,该指南现在说“优先于接口使用抽象基类”
– Reed Copsey
09年4月17日在16:51
虽然,如果您能补充一点一点,那就是它也很接口,它可以应用于任何类。
–cgp
09年4月17日在16:52
@altCognito:认为第二段对此进行了处理。不过,这确实使我想起了接口适用于值类型,因此我添加了这一点。
– Reed Copsey
09年4月17日在16:59
非常感谢您的确切描述。确实非常有帮助。我是新来的。可惜您不能选择两个答案作为“答案”。让我感到困惑的一件事是您对Abstract'base'类的使用。所有抽象类均应作为子类的基类。为什么还要命名“基础”呢?
–侯曼
09年4月17日在17:20
#6 楼
继承考虑一下汽车和公共汽车。他们是两种不同的车辆。但是它们仍然具有一些共同的特性,例如具有转向器,制动器,齿轮,发动机等。
因此,通过继承概念,可以将其表示为以下内容...
public class Vehicle {
private Driver driver;
private Seat[] seatArray; //In java and most of the Object Oriented Programming(OOP) languages, square brackets are used to denote arrays(Collections).
//You can define as many properties as you want here ...
}
现在一辆自行车...
public class Bicycle extends Vehicle {
//You define properties which are unique to bicycles here ...
private Pedal pedal;
}
和一辆汽车...
public class Car extends Vehicle {
private Engine engine;
private Door[] doors;
}
关于继承。如上所述,我们使用它们将对象分类为更简单的Base形式及其子类。
Abstract类
Abstract类是不完整的对象。为了进一步理解它,让我们再次考虑车辆的类比。
可以驾驶车辆。对?但是,不同的车辆以不同的方式行驶。例如,您不能像驾驶自行车一样驾驶汽车。
那么如何表示车辆的驱动功能呢?很难检查它是什么类型的车辆并以其自身的功能驾驶它。您必须在添加新型车辆时一次又一次地更改Driver类。
这里是抽象类和方法的角色。您可以将drive方法定义为抽象的,以告诉每个继承的子代都必须实现此功能。
因此,如果您修改车辆类...
//......Code of Vehicle Class
abstract public void drive();
//.....Code continues
自行车和汽车还必须指定如何开车。否则,代码将无法编译,并且会引发错误。
简而言之。抽象类是部分不完整的类,具有一些不完整的功能,继承子代必须指定它们自己的功能。
Interfaces
接口完全不完整。它们没有任何属性。它们只是表明继承的孩子有能力做某事...
假设您有不同类型的手机。它们每个都有不同的方式来执行不同的功能。例如:打电话给一个人。手机的制造商指定如何进行。手机可以在此处拨打号码-即可以拨打。让我们将其表示为接口。
public interface Dialable {
public void dial(Number n);
}
在这里,Dialable的制造商定义了如何拨打号码。您只需要给它拨一个号码即可。
// Makers define how exactly dialable work inside.
Dialable PHONE1 = new Dialable() {
public void dial(Number n) {
//Do the phone1's own way to dial a number
}
}
Dialable PHONE2 = new Dialable() {
public void dial(Number n) {
//Do the phone2's own way to dial a number
}
}
//Suppose there is a function written by someone else, which expects a Dialable
......
public static void main(String[] args) {
Dialable myDialable = SomeLibrary.PHONE1;
SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....
这里使用接口而不是抽象类,使用Dialable的函数的编写者不必担心其属性。例如:它是否具有触摸屏或拨号盘,是固定座机还是移动电话。您只需要知道它是否可拨号即可。它会继承(或实现)Dialable接口吗?
更重要的是,如果有一天您将Dialable切换为其他接口
......
public static void main(String[] args) {
Dialable myDialable = SomeLibrary.PHONE2; // <-- changed from PHONE1 to PHONE2
SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....
您可以确保代码仍然可以正常工作,因为使用可拨号功能的功能不(也不能)依赖于在“可拨号”界面中指定的详细信息。它们都实现了Dialable接口,而这只是该函数所关心的。
开发人员通常使用接口来确保对象之间的互操作性(可互换使用),只要它们共享一个公共功能(就像您可能会更改一样)即可。只需拨打一个电话就可以拨打座机或手机)。简而言之,接口是抽象类的简单得多的版本,没有任何属性。
此外,请注意,您可以实现(继承)任意数量的接口,但只能扩展(继承)单个父类。
更多信息
抽象类与接口
评论
“接口没有任何属性”是不正确的。
–大眼
17年5月29日在20:06
@ Bigeyes,Java不允许接口中的属性。我认为其他语言也是如此。你能解释更多吗?
– fz_salam
17年5月29日在23:53
我指的是C#/。Net。请看例子
–大眼
17年5月30日在0:11
@Bigeyes for C#接口可以具有属性,这是否会引入多重继承问题?当一个类使用定义了相同属性的多个接口时会发生什么?只是好奇而已
– stackPusher
17年12月21日在5:01
@happycoder:re:“在这里,通过使用接口而不是抽象类,您不必担心它的属性。例如:它是否具有触摸屏或拨号盘,是固定座机还是移动电话。您只需要知道它是否可拨号;它是否继承(或实现)了Dialable接口。” -您可以在代码示例中显示它,也看不到它将如何被继承...
– T.T.T.
18年2月12日在21:33
#7 楼
如果您认为java
是OOP语言来回答此问题,则Java 8版本会导致上述答案中的某些内容过时。现在,java接口可以具有带有具体实现的默认方法。 Oracle网站提供了
interface
和abstract
类之间的主要区别。如果要共享代码,请考虑使用抽象类:
在几个密切相关的类之间。
您希望扩展抽象类的类具有许多公共方法或字段,或者需要除public之外的访问修饰符(例如protected和private)。
您想声明为non -静态或非最终字段。
考虑使用接口,如果:
您希望不相关的类将实现您的接口。例如,许多不相关的对象可以实现
Serializable
接口。您要指定特定数据类型的行为,但不关心谁实现其行为。
您要利用类型的多重继承。
简单来说,我想使用
接口:通过多个不相关的对象实现合同
抽象类:实现多个相关对象之间的行为相同或不同
看看代码示例,以清楚的方式理解事物:如何解释接口和抽象类之间的区别?
#8 楼
面试官正在吠叫一棵奇怪的树。对于C#和Java之类的语言,有区别,但是在诸如C ++之类的其他语言中则没有区别。 OO理论并没有区别这两种语言,只是语言的语法。抽象类是具有实现和接口(纯虚拟方法)的类,它将被继承。接口通常没有任何实现,而只有纯虚函数。
在C#或Java中,没有任何实现的抽象类与接口的区别仅在于用于继承该接口的语法,而且您只能从一个继承。
评论
一周前有人问过我同样的问题,我没有Java经验,但是我已经使用C ++有一段时间了。采访者在提出问题之前没有指定语言,因此我只是解释说,这种情况下的接口是抽象类,没有任何状态或任何实现。我同意这也是一个奇怪的问题。
– dacabdi
17-09-27在12:45
#9 楼
通过实现接口,您将实现组合(“具有”关系)而不是继承(“具有”关系)。这是记住诸如设计模式之类的重要原则,在这种情况下,您需要使用接口来实现行为的组成而不是继承。评论
界面,IMO,更多地实现了“ Acts-as-a”关系。封装比接口更好地实现了组合。
– Reed Copsey
09年4月17日在17:01
我不认为实现接口会受到影响。
– Pavan Dittakavi
2012年12月7日在20:49
另外,接口更可能用于描述“功能”,例如IDisposable。它曾经在类之间共享这些类“能够做”的功能。 IFlyable的更多示例可以通过鸟和飞机来实现。但是Bird可能来自Class Creature,而craft则来自AirCraft。
– Peter.Wang
16年8月30日在7:26
#10 楼
从概念上讲,保持语言特定的实现,规则,好处并通过使用任何一个或两个来实现,可以或不能拥有代码/数据/属性,等等,单一或多个继承,而保留任何编程目标,1-抽象(或纯抽象)类用于实现层次结构。如果您的业务对象在结构上看起来有些相似,仅表示父子(层次结构)类型的关系,则将使用继承/抽象类。如果您的业务模型没有层次结构,则不应使用继承(这里我不是在谈论编程逻辑,例如某些设计模式需要继承)。从概念上讲,抽象类是在OOP中实现业务模型层次结构的一种方法,它与接口无关,实际上将抽象类与接口进行比较是没有意义的,因为两者在概念上是完全不同的,因此在访谈中要求检查类是否是概念,因为当考虑实现时,它们看起来都提供了一些相同的功能,我们程序员通常会在编码方面强调更多。 [也要记住,抽象不同于抽象类]。
2-接口是一种合同,是一组或多组功能代表的完整的业务功能。这就是为什么它被实现而不是被继承。业务对象(是否属于层次结构)可以具有任意数量的完整业务功能。它与抽象类无关,通常意味着继承。例如,人类可以运行,大象可以运行,鸟类可以运行,依此类推,所有这些不同层次的对象都将实现RUN接口或EAT或SPEAK接口。不要进行实现,因为您可能会实现每个实现这些接口的每种类型都有抽象类。任何层次结构的对象都可以具有与其层次结构无关的功能(接口)。
我相信,并不是为了实现多重继承或公开公共行为而发明接口,类似地,纯抽象类也不是推翻接口,而是接口是对象可以执行的功能(通过该接口的功能),而抽象类则代表了层次结构的父级,以产生具有父级核心结构(属性+功能)的子级
当您被问到差异时,实际上是概念上的差异,而不是特定语言实现上的差异,除非明确询问。
我相信,两位面试官都期望这两者之间存在一种直接的区别,当您失败时,他们试图通过将ONE实施为另一种来促使您实现这种区别。
如果只有抽象方法的抽象类怎么办?
评论
这几乎很好地概括了这个问题的答案。
– pranavn
18年4月20日在11:37
实现的功能与扩展的结构,不错!
–harshvchawla
19年8月29日在8:25
#11 楼
我将解释接口和抽象类的深度详细信息。如果您了解接口和抽象类的概述,那么您何时应该使用接口以及何时应该使用抽象类的问题就浮现在脑海中。所以请检查以下解释接口和抽象类的说明。
什么时候应该使用接口?
如果您不了解实现,只是我们有需求规范,那么我们使用接口
当我们应该使用Abstract类时?
如果您知道实现但不完全(部分实现),那么我们就使用Abstract类。
接口
每种方法默认情况下都是公共抽象,意味着接口是100%纯的抽象。
Abstract
可以有具体方法和抽象方法,什么是具体方法,在Abstract类中实现,
抽象类是声明为abstract的类-它可能包含也可能不包含抽象方法。
接口
我们不能将接口声明为受保护的私有
Q。为什么我们不将接口声明为私有且受保护?
因为默认情况下接口方法是公共抽象,所以我们不将接口声明为私有且受保护。
接口方法
我们也不能将接口声明为私有,受保护,最终,静态,同步,本地.....
我会给出原因:
为什么我们之所以没有声明同步方法,是因为我们无法创建接口的对象并且无法进行同步,因此是在对象上进行工作的原因,之所以没有声明同步方法,是因为瞬态工作也带有同步。
瞬态概念也不适用。
抽象
我们很高兴地与public,private最终静态...一起使用。这意味着抽象中没有任何限制。
接口
变量在接口中默认情况下声明为公共静态最终变量,因此我们也不将变量声明为私有,受保护的变量。
可变修饰符也不适用于接口,因为接口变量默认情况下为公共静态最终变量最后一个变量,一旦将值分配给变量,并且在将变量声明为接口后就必须分配变量,就不能更改值。
volatile变量会不断变化,因此它是opp。最终是因为我们不在接口中使用volatile变量的原因。
Abstract
Abstract变量无需声明公共静态final。
希望这篇文章对您有用。
评论
我不同意这一点:抽象类必须至少具有一个抽象方法。只要实现它,就有可能没有Abstract方法的Abstract类。参考:抽象类是被声明为抽象的类-它可能包含也可能不包含抽象方法。参考资料:docs.oracle.com/javase/tutorial/java/IandI/abstract.html
–德夫纳
2014年12月2日,7:10
您在谈论技术细节和实施,不是在一般OOP方面回答问题
– Billal Begueradj
18年8月18日在7:14
#12 楼
对于.Net,您对第二个面试官的回答也对第一个面试官的回答...抽象类可以有实现,AND状态,接口不能...
编辑:另一方面,我什至不使用短语“子类”(或“继承性”短语)来描述“定义为实现”接口的类。对我而言,接口是对合同的定义,如果已经定义了一个类来“实现”该接口,则该类必须遵循该合同。它不会继承任何东西...您必须自己显式添加所有内容。
评论
是!州!那就是第二位面试官用怪异的方式在界面内说“公共变量”的意思。天哪!抽象类可以有状态,接口不能有状态!是的,其他所有人也都同意他们的继承方式之间的差异,我忘记提及了,但是后来已经弄清楚了。 :) 谢谢大家!
–侯曼
09年4月17日在17:11
不仅仅是状态。抽象类可以具有实现。即,他们可以在其中包含带有代码的方法,这些方法实际上可以运行并执行某些操作,而这些方法会被基类的实例继承和执行。
–查尔斯·布雷塔纳(Charles Bretana)
2011年10月10日15:51
从某种意义上讲,甚至还可以实例化Abstract类,而只需要使用派生类定义而不是直接实例化即可。但是在抽象类中定义的状态变量在通过对派生类的实例进行新创建而创建的对象中实例化。该实例既是抽象类的实例,又是派生类的实例-毕竟是从它派生的。对于接口,这都不是正确的。
–查尔斯·布雷塔纳(Charles Bretana)
17/12/6在16:32
当您新建一个定义为实现接口的类的实例时,它不是该接口的“实例”,所有语法都会使编译器检查该类的代码并确保每种行为(方法,属性,事件,eventHandler等),该接口定义的内容已在该类的代码中实现。
–查尔斯·布雷塔纳(Charles Bretana)
17年6月6日在16:35
#13 楼
接口:如果要对可能相互关联或不相互关联的组件隐含规则,则应使用>允许多重继承
通过不公开上下文中使用的确切类型的对象来提供抽象
通过合同的特定签名提供一致性
缺点:
必须实现所有定义的契约
不能有变量或委托
一旦定义就不能不破坏所有的类而不能更改
Abstract Class:应该用于希望彼此相关的组件具有某些基本或默认行为或实现的地方
优点:
比接口更快捷
有实现的灵活性(可以完全或部分实现)
可以轻松更改而不会破坏派生类
缺点:
实例化的
不支持多重继承
评论
定义更快。重要吗?这到底是什么意思?在抽象类上进行函数调用的操作码比在接口上进行函数调用的操作码快吗?
–denis631
2月11日17:38
@ denis631抽象类比接口快一点,因为interface方法中涉及搜索和调用。阅读此代码ranch.com/t/503450/java/abstract-class-faster-interface
– bourax网站管理员
2月12日18:12
#14 楼
我认为他们不喜欢您的回答,因为您提供了技术差异而不是设计差异。这个问题对我来说就像一个巨魔问题。实际上,接口和抽象类的性质完全不同,因此您无法真正进行比较。我将向您介绍接口的作用和抽象类的作用。interface:用于确保协定并在类之间建立低耦合,以便具有更可维护,可扩展和可测试的应用程序。抽象类:仅用于分解具有相同责任的类之间的某些代码。请注意,这是在OOP中多继承是一件坏事的主要原因,因为类不应承担许多责任(请改用合成)。
所以接口具有真正的架构作用,而抽象类几乎只是实现的一个细节(当然,如果正确使用的话)。
#15 楼
接口:
我们不实现(或定义)方法,而是在派生类中实现。
我们不在接口中声明成员变量。
接口表示HAS-A关系。这意味着它们是对象的掩码。
抽象类:
我们可以在抽象类中声明和定义方法。
我们隐藏了以下对象的构造函数它。这意味着没有直接从中创建对象。
抽象类可以容纳成员变量。
派生类继承给抽象类,这意味着派生类中的对象没有被屏蔽,它继承了抽象类。在这种情况下的关系是IS-A。
这是我的看法。
#16 楼
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?
变量默认情况下,接口中的public静态和最终。如果抽象类中的所有变量都是公共的,该问题可能会被框起来?好吧,它们仍然可以是非静态的和非最终的,与接口中的变量不同。
最后我要在上面提到的那些上再加一点-抽象类仍然是类,并且属于单个继承树,而接口可以存在于多个继承中。
#17 楼
Jeffrey Richter通过C#从CLR复制了它。我经常听到一个问题,“我应该设计基本类型还是接口?”答案并不总是很明确。
以下一些准则可能对您有帮助:
■■IS-A与CAN-DO关系类型只能继承一个类型实施。如果派生的
类型不能与基本类型声明IS-A关系,请不要使用基本类型;使用接口。
接口表示CAN-DO关系。如果CAN-DO功能似乎属于各种对象类型,请使用接口。例如,一个类型可以将其自身的实例转换为另一种类型(IConvertible),一个类型可以将其自身的实例序列化(ISerializable),
等。请注意,值类型必须从System.ValueType派生,因此不能
从任意基类派生。在这种情况下,您必须使用CAN-DO关系
并定义一个接口。
■■易于使用作为开发人员,您通常更容易定义从基本类型要比
实现一个接口的所有方法。基本类型可以提供很多功能,因此派生类型可能只需要对其行为进行较小的修改即可。如果提供接口,则新类型必须实现所有成员。
■■一致的实现无论接口合同的文档记载如何,
每个人都不太可能实现正确签约100%。实际上,COM
遇到了这个问题,这就是为什么某些COM对象只能在
Microsoft
Word或Windows Internet Explorer中正常工作的原因。通过为基本类型提供良好的默认实现,您可以开始使用有效且经过良好测试的类型。然后您可以
修改需要修改的零件。
■■版本控制如果将方法添加到基本类型,则派生类型将继承新方法,
您可以使用一种有效的类型开始,甚至不必重新编译用户的源代码。
在接口中添加新成员会强制接口的继承者更改其源代码,并且重新编译。
评论
@AbdullahShoaib是-一个人可以做但不能做的事,这里有所不同。这是基本原因,我们需要接口。可以做的行为也将成为抽象类的一部分。
–过度兑换
2014年11月13日17:24
#18 楼
接口定义一项服务或一组服务的合同。它们以水平方式提供多态性,因为两个完全不相关的类可以实现相同的接口,但可以互换地用作它们实现的接口类型的参数,因为这两个类都承诺满足该接口定义的服务集。接口不提供任何实现细节。抽象类为其子类定义基本结构,并可以选择部分实现。抽象类以垂直但有方向的方式提供多态性,因为任何继承了抽象类的类都可以被视为该抽象类的实例,但不能反过来。抽象类可以并且经常确实包含实现细节,但是不能单独实例化-只有它们的子类可以被“更新”。
C#也允许接口继承。 />
评论
使用术语“水平”和“垂直”可以很清楚地想象出差异。
–无限
18年1月24日在8:09
#19 楼
大多数答案都集中在抽象类和接口之间的技术差异上,但是从技术上讲,接口基本上是一种抽象类(一个没有任何数据或实现的抽象类),我认为概念上的差异要有趣得多,这可能就是面试官在追赶。接口是协议。它指定:“这就是我们彼此交谈的方式”。它不能有任何实现,因为它不应该有任何实现。是合同就像C中的
.h
头文件一样。抽象类是不完整的实现。一个类可以实现也可以不实现接口,而抽象类则不必完全实现它。没有任何实现的抽象类是无用的,但完全合法。
基本上,任何类(无论是否抽象)都与它的本质有关,而接口与它的使用方式有关。例如:
Animal
可能是一个抽象类,它实现一些基本的代谢功能,并在没有给出实现的情况下指定用于呼吸和运动的抽象方法,因为它不知道它应该通过g还是肺呼吸,以及它是否飞行,游泳,行走或爬行。另一方面,Mount
可能是一个界面,它指定您可以骑乘动物而无需知道它是哪种动物(或根本不是动物!)。事实在幕后,接口基本上是只具有抽象方法的抽象类,没关系。从概念上讲,它们扮演着完全不同的角色。
#20 楼
您可能已经从专家那里获得了理论知识,所以我在这里不再赘述,而是让我用一个简单的示例来说明,其中我们可以使用/不能使用Interface
和Abstract class
。考虑您正在设计一个应用程序,以列出汽车的所有功能。在各个方面,您都需要共同的继承,因为所有汽车都拥有一些属性,例如DigitalFuelMeter,空调,座椅调节等。同样,我们仅需要对某些类进行继承,因为诸如制动系统(ABS,EBD)之类的某些属性仅适用于某些汽车。
下面的类充当所有汽车的基础类:
public class Cars
{
public string DigitalFuelMeter()
{
return "I have DigitalFuelMeter";
}
public string AirCondition()
{
return "I have AC";
}
public string SeatAdjust()
{
return "I can Adjust seat";
}
}
考虑到我们对每辆汽车都有一个单独的类。
/>
public class Alto : Cars
{
// Have all the features of Car class
}
public class Verna : Cars
{
// Have all the features of Car class + Car need to inherit ABS as the Braking technology feature which is not in Cars
}
public class Cruze : Cars
{
// Have all the features of Car class + Car need to inherit EBD as the Braking technology feature which is not in Cars
}
考虑到我们需要一种方法来继承Verna和Cruze汽车的制动技术(不适用于Alto)。尽管两者都使用制动技术,但“技术”不同。因此,我们正在创建一个抽象类,其中该方法将声明为Abstract,并且应在其子类中实现。
public abstract class Brake
{
public abstract string GetBrakeTechnology();
}
现在,我们尝试从这个抽象类和制动系统的类型在Verna和Cruze中实现:
public class Verna : Cars,Brake
{
public override string GetBrakeTechnology()
{
return "I use ABS system for braking";
}
}
public class Cruze : Cars,Brake
{
public override string GetBrakeTechnology()
{
return "I use EBD system for braking";
}
}
看到上面两个类中的问题吗?它们从C#.Net不允许的多个类继承,即使该方法在子代中实现也是如此。这里是需要接口的。
interface IBrakeTechnology
{
string GetBrakeTechnology();
}
实现如下:
public class Verna : Cars, IBrakeTechnology
{
public string GetBrakeTechnology()
{
return "I use ABS system for braking";
}
}
public class Cruze : Cars, IBrakeTechnology
{
public string GetBrakeTechnology()
{
return "I use EBD system for braking";
}
}
现在Verna和Cruze可以借助Interface借助自己的制动技术实现多重继承。
评论
由于示例,这是最好的解释之一。
–亚当·门多萨(Adam Mendoza)
16年7月26日在6:42
这对我来说是有意义的,而无需绞尽脑汁。我只是想为学生们举一个汽车的例子。感谢您抽出宝贵的时间来整理这些内容。
– tazboy
17年1月20日在13:45
#21 楼
接口是用于执行特定行为的轻量级方法。这是一种思考方式。#22 楼
这些答案太长了。接口用于定义行为。
抽象类用于定义事物本身,包括其行为。这就是为什么我们有时会创建一个带有继承接口的一些额外属性的抽象类的原因。
这也解释了为什么Java只支持类的单一继承,而对接口没有任何限制。因为一个具体的对象不能是不同的事物,但是它可以具有不同的行为。
#23 楼
1)接口可以看作是一个纯抽象类,它是相同的,但是尽管如此,实现一个接口并从抽象类继承还是不一样。从这个纯抽象类继承时,您将定义一个层次结构->继承,如果您实现的不是接口,则可以实现任意数量的接口,但只能从一个类继承。2)您可以在接口中定义属性,因此实现该接口的类必须具有该属性。例如,
public interface IVariable
{
string name {get; set;}
}
实现该接口的类必须具有这样的属性。
#24 楼
尽管这个问题已经很老了,但我想补充一点,以便支持接口:可以使用任何依赖注入工具来注入接口,其中很少有人支持Abstract类注入。
评论
我相信您的意思是DI工具可以注入实现接口的类。一些这样的工具还可以注入派生自抽象类的类,或者您说那是不可能的?
–约翰·桑德斯(John Saunders)
2012年8月31日14:30
#25 楼
从我的另一个答案中,主要涉及何时使用一个与另一个:根据我的经验,当您有多个类时,最好使用接口
每个都需要响应相同的一个或多个方法,以便它们可以与其他代码互换使用,而这些代码将针对这些类的公共接口编写。接口的最佳用法是在
协议很重要但每个类的基础逻辑可能不同的情况下。如果您否则会
复制逻辑,请考虑使用抽象类
或标准类继承
。
#26 楼
接口类型与抽象基类来自Pro C#5.0和.NET 4.5 Framework书。
接口类型似乎与抽象基类非常相似。回想一下
,当一个类被标记为抽象时,它可以定义任意数量的抽象成员,以为所有派生类型提供
多态接口。但是,即使一个类确实定义了一组抽象
成员,也可以自由定义任意数量的构造函数,字段数据,非抽象成员(具有
实现),等等。另一方面,接口仅包含抽象成员定义。
由抽象父类建立的多态接口受到一个主要限制
,因为只有派生类型支持抽象父定义的成员。但是,在较大的
软件系统中,开发在System.Object之外没有共同父类的多个类层次结构是很常见的。鉴于抽象基类中的抽象成员仅适用于派生的
类型,我们无法配置不同层次结构中的类型以支持相同的多态
接口。举例来说,假设您定义了以下抽象类:
public abstract class CloneableType
{
// Only derived types can support this
// "polymorphic interface." Classes in other
// hierarchies have no access to this abstract
// member.
public abstract object Clone();
}
给出此定义,只有扩展CloneableType的成员才能支持Clone()
方法。如果您创建了一组不扩展该基类的新类,则将无法获得此
多态接口。另外,您可能还记得C#不支持类的多重继承。
因此,如果您要创建的是-a Car和is-a CloneableType的MiniVan,则无法这样做:
// Nope! Multiple inheritance is not possible in C#
// for classes.
public class MiniVan : Car, CloneableType
{
}
您可能会猜到,接口类型可以解决。定义接口后,可以
由任何类或结构,任何层次结构,任何名称空间或任何程序集中的接口实现
(以任何.NET编程语言编写)。如您所见,接口是高度多态的。
考虑在System名称空间中定义的标准.NET接口ICloneable。该
接口定义了一个名为Clone()的方法:
public interface ICloneable
{
object Clone();
}
#27 楼
回答第二个问题:public
中定义的interface
变量默认是static final
,而public
类中的abstract
变量是实例变量。#28 楼
当然,了解OOP中的接口和抽象类的行为(以及语言如何处理)很重要,但是我认为了解每个术语的确切含义也很重要。您能想象if
命令不能完全按照术语的含义工作吗?同样,实际上,某些语言正在减少甚至更大程度地减少界面和抽象之间的差异……如果有一天偶然,两个术语的操作几乎完全相同,至少您可以定义自己应该在哪里(以及为什么) 如果您通读一些词典和其他字体,可能会发现同一术语具有不同的含义,但具有一些常见的定义。我认为我在本站点中发现的这两种含义确实非常非常好并且很合适。
接口:
一种事物或情况,可以分开,有时不兼容元素可以有效地进行协调。
摘要:
某种东西本身就集中了更广泛或更普遍的事物或某些事物的本质素质东西本质。
示例:
您买了一辆汽车,它需要燃料。
您的汽车模型是
XYZ
,属于流派ABC
,因此它是混凝土车,是汽车的特定实例。汽车不是真正的物体。实际上,它是创建特定对象的一组抽象标准(质量)。简而言之,Car是一个抽象类,它是“某种东西,它本身集中了任何更广泛或更普遍的东西的本质素质”。 只能使用符合汽车手册规格的燃料来填充汽车油箱。实际上,没有任何限制可以放任何燃料,但发动机只能使用指定的燃料才能正常工作,因此最好遵循其要求。要求说,它像其他同类
ABC
的汽车一样接受标准燃料。在面向对象的视图中,不应将类别
ABC
的燃料声明为类别,因为那里没有特定类型汽车的具体燃料。尽管您的汽车可以接受抽象类的Fuel(燃料)或VehicularFuel(车辆燃料),但您必须记住,您现有的仅有部分车辆燃料符合规范,即符合您的汽车手册要求的规范。简而言之,他们应该实现接口ABCGenreFuel
,该接口“ ...使单独的,有时是不兼容的元素能够有效地进行协调”。 附录
此外,我认为您应该牢记“类”一词的含义,该类(来自前面提到的同一站点):
类:
由于共同的属性,特征,品质或特质而被视为一个团体的许多人或事物; kind;
这样,一个类(或抽象类)不应仅表示公共属性(如接口),而应表示具有公共属性的某种组。接口不需要代表一种。它必须代表通用属性。这样,我认为类和抽象类可以用来表示不应该经常改变其外观的事物,例如人类哺乳动物,因为它代表了某些种类。种类不应该经常改变自己。
评论
太多的绒毛,不要让声音听起来比以前更令人困惑。
– ganjeii
16 Dec 2'在19:09
#29 楼
从编码角度来看,如果Abstract类仅具有抽象方法,则接口可以替换Abstract类。否则将Abstract类更改为接口意味着您将失去继承所提供的代码可重用性。从Design Perspective
如果它是Abstract类,则将其保留为Abstract类。 “是”关系,您需要部分或全部功能。如果是“应该做”的关系,则将其保留为接口。
确定您需要的内容:仅执行策略,或代码可重用性和策略。
#30 楼
其他一些差异:抽象类可以具有静态方法,属性,字段等,而运算符,接口则不能。
Cast运算符允许从抽象类强制转换,但不能允许从接口强制转换。
几乎可以使用抽象类,即使它从未实现(通过其静态成员),也不能单独使用接口方式。
评论
在Java中,接口可以具有成员变量,但是默认情况下它们成为公共静态..so接口可以具有静态字段
– Jitendra Vispute
13年6月10日在11:12
是的,接口可以具有静态字段。 BUT接口不能具有静态方法。
–学习者
2013年7月5日在11:42
评论
尽管我认为了解两者之间的差异很重要,但imo并不是一个很好的面试问题。除非工作是写有关面向对象的书。最好不要为那些蝙蝠工作。@Alan:我实际上很喜欢将其作为面试问题,但我不会对这种人产生疑问-我可能会更喜欢发布它,例如“在定义层次结构时,您将在抽象基类上选择一个接口吗? ”或类似内容。
也许他们是在寻求更专注于设计的答案之后……虽然像您一样,我会将其视为技术问题。
此处的表格格式差异不错:mindprod.com/jgloss/interfacevsabstract.html
@Kave:我坚持认为您不能在接口内使用公共变量。我认为接口可以具有公共变量。实际上,接口中的变量是自动公开的和最终的。