java - 抽象类与所有方法抽象和接口(interface)之间的区别?

标签 java oop interface abstract-class

我有一次面试,面试官首先问我抽象类与所有抽象方法和接口(interface)有什么区别。

我回复说以后如果要继承什么东西你已经扩展了一个类就不行了。

然后,他表示在这种情况下,永远不必扩展任何其他类,而您必须实现契约。在这种情况下,抽象类和接口(interface)哪个更好?

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

最佳答案

声明接口(interface)表示契约的答案是 Not Acceptable 。 这就是我们给 Junior 的答案,因为如果没有太多的架构经验和阅读大量经典书籍,很难清楚地弄清楚抽象类的本质和接口(interface)的本质之间的区别。 任何具有 public 方法的抽象类都充当契约和接口(interface)。

在 99% 的情况下,不提供任何实现的抽象类代表对象的角色
一个接口(interface)代表一个角色
每个对象可能有几个不同的角色,这些角色不应捆绑在一起,而是由相关对象组成。

我用这个例子来解释这一点:

你的面试官可能会说:
我有一个可以走路的机器人和一个也可以走路的

所以基于这个案例,他问你:我应该在抽象基类或接口(interface)中提取行走特征,知道实现没有共同点吗?

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

为什么?让我们看看接下来的期待:
可以吃东西,但显然机器人不能吃,甚至不需要。

如果您使用抽象类实现行走功能会怎样?你最终会得到:

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 接口(interface):

public interface Feedable {
  void eat();
} 

签名变为:public Human extends Biped implements Feedable { 显然,让一个角色通过类实现而另一个通过接口(interface)实现是没有意义和令人困惑的。

这就是为什么只要我们有选择,就真正首选从接口(interface)开始。

有了接口(interface),我们可以通过组合轻松地对角色进行建模。

所以最终的解决方案是:

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(){
     //...
   }    
}

是不是让你想起了接口(interface)隔离原则? ;)

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

关于java - 抽象类与所有方法抽象和接口(interface)之间的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23302920/

相关文章:

java - 如何读取放置在 war 之外的属性文件?

java - 在 JAX-RS 资源中组合 @Context 和 @RolesAllowed?

java - 编写android :button programmatically

c# - 这种聚合设计模式有名称吗?

java - 使用带有默认方法的新 Java8 接口(interface)

java - 标记界面的目的是什么?

java - 带标题的 JPanel

java - java中的继承 : object state and behavior

javascript - 检查 Javascript 命名空间中的类类型是否可用

Java 泛型类型扩展多个类