抽象类与所有方法抽象和接口之间的区别?

时间:2014-04-25 20:58:37

标签: java oop interface abstract-class

我接受采访时,面试官首先问我抽象类与抽象方法和界面之间的区别。

我回答说,如果将来要求继承某些内容,如果您已经扩展了课程,那么您将无法继续。

然后,他说这是一种情况,人们永远不必延长任何其他类,你必须实施合同。在这种情况下,哪个更好,一个抽象类或接口?

我告诉他你可以使用其中任何一个,但他不满意。我无法理解为什么 - 我相信这是开发人员/设计选择。

7 个答案:

答案 0 :(得分:6)

表示接口代表合同的答案是不可接受的。 这就是我们给Junior的答案,因为它可能太复杂,无法清楚地弄清楚抽象类的本质与没有太多架构经验的界面的本质之间的区别,也没有阅读很多经典书籍。 任何带有public方法的抽象类都可以作为契约,也可以作为接口。

不提供任何实现的抽象类在99%的情况下表示对象的角色
界面代表角色 每个对象可能有几个不同的角色,不应该绑定在一起,而是由相关对象组成。

我用这个例子解释了这个

你的面试官可以说:
我有一个可以走路的Robot和一个可以走路的Human

基于这种情况,他问你:我应该在抽象基类或界面中提取步行特征,知道实现没有任何共同之处吗?

您认为......“哦,我知道:在这种情况下,使用抽象方法walk()创建一个抽象类,然后显然与使用walk()方法声明接口相同。 “
所以你的回答肯定是:“这是开发者的选择!” 这真的不是一个永远有效的答案。

为什么呢?让我们看看下一个期望:
Human可以吃,但显然Robot不能,甚至不需要。

如果您使用抽象类实现了步行功能,该怎么办?你最终会得到:

public abstract class Biped {  
  public void abstract walk();
} 

public Robot extends Biped {
   public void walk() {
     //walk at 10km/h speed
   }
}

public Human extends Biped {
   public void walk() {
     //walk at 5km/h speed
   }
}

如何插入eating功能?你被卡住是因为你不能在Biped基类中实现它,因为它会破坏 Liskov替换原则,因为Robot不吃! 而且由于已知的Java规则,您不能指望Human扩展另一个基类。

当然,您可以添加仅专用于Human的特定Feedable界面:

public interface Feedable {
  void eat();
} 

签名变为:public Human extends Biped implements Feedable { 显然,通过一个接口实现一个角色并通过一个接口实现另一个没有任何意义和困惑。

这就是为什么只要我们有选择,首先从界面开始就是首选。

通过界面,我们可以通过编写轻松地模拟角色

因此,最终的解决方案是:

public interface Walkable {
   void abstract walk();
} 

public interface Feedable {
   void eat();
} 

public Robot implements Walkable {
   public void walk() {
     //walk at 10km/h speed
   }
}

public Human implements Walkable, Feedable {
   public void walk() {
     //walk at 5km/h speed
   }

   public void eat(){
     //...
   }    
}

它不会提醒您接口隔离原则吗? ;)

总之,如果指定 IS-A 关系,则使用抽象类。 如果您意识到您要建立角色(假设 IS-CAPABLE-OF 关系),请使用界面。

答案 1 :(得分:1)

以下是不同之处:

  1. 一个类可以扩展完全抽象的类,但可以实现任意数量的接口。
  2. 抽象类可以有受保护的,私有的(不适用于您的问题),包和公共方法,但接口只能有公共方法。
  3. 抽象类可以包含实例变量(通常称为数据成员或属性),而接口只能包含静态变量。
  4. 问题的答案:“blah永远不会延长blah实现合同等等”是:“如果我需要实例变量和/或非公共方法,我会使用抽象类,否则我会使用接口”。

答案 2 :(得分:0)

接口是创建合同的自然方式,因为他们强制您实现他们定义的方法。

除此之外,您可以在想要为类添加新接口的情况下实现任意多个。

答案 3 :(得分:0)

我不能说出你的面试官的想法,但是界面更像是一个合同"而抽象基类虽然也可以扮演这个角色,但更适合于层次结构或IS-A关系。例如。 Apple IS-A Fruit,Pear IS-A Fruit等等。但是你是对的,在这种情况下它们可以互换用于实际目的,但OO纯粹主义者可能不想使用抽象类,除非他们表达了IS-A的关系。

答案 4 :(得分:0)

要记住的一件事是能够为接口提供钻石继承。

考虑这个界面层次结构:

interface Base{}

interface Sub1 extends Base{}

interface Sub2 extends Base{}

interface SubSub extends Sub1, Sub2{}

抽象类也不可能这样做:

abstract class Base{}

abstract class Sub1 extends Base{}

abstract class Sub2 extends Base{}

// NOT ALLOWED! can only extend one class
// abstract class SubSub extends Sub1, Sub2{}

这在C ++中是允许的(虽然很难做到正确)。我想他可能一直在为此钓鱼。通常,这是我总是尝试编写接口层次结构而不是类层次结构的最终原因。

答案 5 :(得分:0)

对于第一种情况,我选择了抽象类的接口,所有方法都是抽象的,因为接口让我可以在将来为我的实现类扩展一些其他(抽象)类。

对于第二种情况,如果你真的不希望你的具体课程扩展到任何其他课程,并且也想要实施"合同,你可以使用抽象的所有方法抽象类。

答案 6 :(得分:0)

我看到这样的问题已经回答了。顺便说一句,我想分享一下到目前为止我认为最好的解释。

从哈努曼特(Khanumant)的德什穆克(Deshmukh)复制并粘贴了下面的波纹管文本。 OCP Oracle认证专业Java SE 11程序员I考试基础1Z0-815:通过OCP Java 11开发人员认证第1部分考试1Z0-815的学习指南(第319页)。 Enthuware。 Edição做Kindle。

13.2从接口继承(包括抽象类)中区分类继承13.2.1接口和抽象类之间的区别☝

“接口和抽象类之间的区别是什么”通常是Java“技术检查”中提出的第一个问题。虽然是简单的破冰船,但判断候选人对OOP的理解也是一个很好的问题。候选人通常会开始模仿技术上的差异,例如接口不能具有方法实现(从Java 8开始就可以实现),而抽象类则可以。接口不能具有静态方法(从Java 8开始就可以)或实例字段,而抽象类则可以等等。所有这些都是正确的,但并不十分令人印象深刻。接口和抽象类之间的根本区别在于,接口仅定义行为。除了它的行为方式,接口没有告诉您有关实际对象的任何信息。另一方面,抽象类定义一个对象,该对象进而驱动行为。如果您理解此概念,那么关于它们的其他所有内容都将落在原处。例如,“运动”是由各种对象(例如汽车,猫或股票价格)显示的行为。这些对象除了移动外没有其他共性。反过来说,如果您得到一个“移动”的对象,那么您将不会知道要处理哪种对象。它可能是汽车,猫或股票价格。如果要捕获Java中的这种行为,则可以使用名为Movable的接口以及名为move()的方法。另一方面,如果您谈论汽车,则物体的图片立即开始在您的脑海中形成。您可以感觉到,汽车将具有发动机,车轮和运动能力。您从直觉上知道,即使股票价格或Cat都移动了,它们也不能成为汽车。当您确定了概念对象时,您不必担心其行为时,抽象类正是用于此目的。行为种类自动流动。如果创建一个名为Automobile的抽象类,则几乎可以肯定它会具有诸如移动,转弯,加速或制动的方法。它将具有用于捕获内部细节的字段,例如引擎,车轮和齿轮。您只要说出“汽车”一词即可获得所有这些。通过以上讨论,应该清楚接口和抽象类是不可互换的。即使没有非抽象方法的抽象类在功能上与接口相似,但两者在本质上是不同的。如果要捕获行为,则必须使用接口。如果要捕获概念对象,则必须使用抽象类。