我何时必须使用接口而不是抽象类?

时间:2013-05-27 22:30:20

标签: java oop inheritance interface abstract-class

我想知道何时应该使用接口。

让我们考虑以下事项:

public abstract class Vehicle {
   abstract float getSpeed();
}

和:

public interface IVehicle {
  float getSpeed();
}

我可以很容易地实现它们,它们具有相同的功能......但是我也可以在我的车辆类中添加一些变量,这些变量可能应该用在车辆中(maxSpeed,carType ......)

使用接口的原因是什么?

谢谢!

编辑:我在另一个帖子中找到了关于它的一个很好的链接:http://www.thecoldsun.com/en/content/01-2009/abstract-classes-and-interfaces

18 个答案:

答案 0 :(得分:95)

Java How to Program关于抽象类:

  

因为它们仅用作继承层次结构中的超类,   我们将它们称为抽象超类。 这些课程不可能   用于实例化对象,因为抽象类是不完整的。   子类必须声明“缺失部分”成为“具体”类,   您可以从中实例化对象。否则,这些子类也是如此   将是抽象的。

回答你的问题“使用接口的原因是什么?”:

  

抽象类的目的是提供适当的超类   其他类可以从中继承并共享一个共同的设计。

与界面相反:

  

接口描述一组可在其上调用的方法   对象,但不提供所有的具体实现   方法 ...一旦类实现了一个接口,该类的所有对象都有   与接口类型的is-a关系,以及的所有对象   class保证提供由...描述的功能   接口。对于该类的所有子类也是如此。

因此,为了回答你的问题“我想知道何时应该使用接口”,我认为你应该在需要完整实现时使用接口,并在需要部分设计(可重用性)时使用抽象类

答案 1 :(得分:15)

来自Oracle tutorials

与接口不同,抽象类可以包含非 staticfinal的字段,并且它们可以包含已实现的方法。这些抽象类与接口类似,不同之处在于它们提供部分实现,将其留给子类来完成实现。如果抽象类只包含抽象方法声明,则应将其声明为接口。

可以通过类层次结构中的任何位置实现多个接口,无论它们是否以任何方式彼此相关。例如,可以考虑ComparableCloneable

相比之下,抽象类最常被子类化以共享实现。单个抽象类由具有许多共同点的类似类(抽象类的实现部分)进行子类化,但也有一些差异(抽象方法)。

答案 2 :(得分:8)

许多情况都可以在两种类型中实现。

当您想要定义必须至少具有基本功能的类时,接口非常有用。就像一个真实的接口,例如USB。

interface USB {
    public function sendPower(); //charge iphone for example
    public function sendData(); //itunes
    public function recieveData();
}

当有多种方法可以实现对象时,请使用抽象类。

abstract class MobilePhone {
    public function isIphone();

    public function charge() {
        //get some power, all phones need that
    }
}

class iPhone extends MobilePhone {
    public function isIphone() { return true; }
}

答案 3 :(得分:7)

您可能会多次考虑在抽象实现上使用接口

  • 当可用的抽象实现不能满足您的需求并且您想创建自己的
  • 当你有一个现有的类(从其他类扩展)并且你想实现接口的功能时

一般来说,引入接口是为了克服缺乏多重继承性等问题

答案 4 :(得分:3)

自Java 8发布以来,界面支持默认方法,接口抽象类之间的差距已经缩小,但仍然存在重大差异。

  1. 界面中的变量为 public static final 。但抽象类可以有其他类型的变量,如 private,protected

  2. 界面中的方法是公开公共静态,但抽象类中的方法可以是私有受保护

  3. 使用抽象类来建立相互关联的对象之间的关系。使用界面来建立不相关的类之间的关系。

  4. 对于java中的 interface 的特殊属性,请查看此article。如果要使用@override,接口中的默认方法的静态修饰符会导致派生错误中的编译时错误

    本文解释了为什么在java 8中引入了默认方法:在Java 8中增强Collections API以支持lambda表达式。

    还要查看oracle文档,以更好的方式理解差异。

    通过代码示例查看这些相关的SE问题,以便更好地理解事物:

    How should I have explained the difference between an Interface and an Abstract class?

答案 5 :(得分:3)

来自The Java™ Tutorials - Abstract Classes Compared to Interfaces

  

您应该使用哪些,抽象类或接口?

     
      
  • 如果这些语句中的任何一个适用于您的情况,请考虑使用抽象类:      
        
    • 您希望在几个密切相关的类之间共享代码。
    •   
    • 您希望扩展抽象类的类具有许多常用方法或字段,或者需要除公共之外的访问修饰符(例如protected和private)。
    •   
    • 您想要声明非静态或非最终字段。这使您可以定义可以访问和修改它们所属对象状态的方法。
    •   
  •   
  • 如果这些陈述中的任何一个适用于您的情况,请考虑使用接口:      
        
    • 您希望不相关的类会实现您的界面。例如,接口ComparableCloneable由许多不相关的类实现。
    •   
    • 您希望指定特定数据类型的行为,但不关心谁实现其行为。
    •   
    • 您希望利用类型的多重继承。
    •   
  •   
     

JDK中抽象类的一个示例是AbstractMap,它是集合框架的一部分。其子类(包括HashMapTreeMapConcurrentHashMap)共享许多方法(包括getputisEmpty,{{1 {}}}定义的{}}和containsKey}。

答案 6 :(得分:2)

如果要为一组子类定义模板,请使用抽象类,至少要有一些实现代码调用子类可以使用。

如果要定义其他类可以播放的角色,请使用界面 ,无论这些类在继承树中的位置

扩展抽象类

实施接口:)

界面中,所有字段都会自动public static final,所有方法都是public抽象类可以让你在这里有一点灵活性。

答案 7 :(得分:1)

考虑Java:

接口:

  • 是一个基本的OOP抽象。
  • 通常(但不总是)会产生比抽象类更清晰的代码。
  • 可以通过多个具体类来实现,以适应不同的情况。
  • 可以直接实现调用多重继承的场景。
  • 可以更容易地模拟出来进行测试。
  • 对JDK代理有用(请参阅java.lang.reflect.Proxy)。

这些只是接口与抽象类的很长的优缺点列表的开头。

答案 8 :(得分:1)

这是优秀书籍的直接摘录' Thinking in Java'布鲁斯·埃克尔(Bruce Eckel)。

  

[..]你应该使用界面还是抽象类

     

好吧,一个接口为您提供了抽象类的好处和接口的好处,因此如果可以创建没有任何方法定义或成员变量的基类,您应该总是更喜欢接口到抽象类。

     

事实上,如果您知道某些东西将成为基类,那么您的第一选择应该是使其成为一个接口,并且只有当您被迫拥有方法定义或成员变量时才应该更改为抽象类

答案 9 :(得分:1)

这个问题的答案非常简单,无论我们用接口做什么都可以用抽象类同步来完成...所以当使用接口时,答案就在于多重继承的C#限制。当你只有声明的契约(摘要)并且希望你的子类实现它时,请使用接口,因为如果你在这种情况下使用抽象类,你就不能继承另一个类,如果你想继承一个类,你就会陷入困境更多类,但你可以实现尽可能多的接口。

答案 10 :(得分:1)

如果您使用的是JDK 8,则没有理由使用抽象类,因为无论我们使用抽象类,我们现在可以使用默认方法来使用接口。 如果你使用抽象类,你必须扩展它,并且有一个限制,你只能扩展一次。但是如果你使用界面,你可以实现任意多个。

默认情况下,接口是一个抽象类,所有方法和构造函数都是公共的。

答案 11 :(得分:0)

接口基本上是在两方合作时使用的,一方希望隐藏其他东西(或者只是想显示他班级的某些部分)。然后我们使用接口例如。 在jdbc jdbc供应商为我们提供了一些bcoz接口,他们希望隐藏我们的一切。

抽象类仅在我们想要支持多个类中的公共行为时才使用...或者想要使用一些未实现的方法提供一些预先实现的实现(方法应该是抽象的)。 例如。 servlet接口中的http servlet是一个抽象类bcoz这个类实现了servlet接口,除了它的服务方法...所以这个类帮助我们得到一些预处理接口方法......

答案 12 :(得分:0)

实际上,接口和抽象类仅用于指定一些合同/规则,这些合同/规则只显示它们的子类如何。

大多数情况下,我们知道接口是一个纯粹的抽象。在那里你不能用body指定一个方法。这个特殊点是抽象类的优点。抽象类中的元素你有权用body指定方法而没有body -好。

因此,如果你想指定关于你的子类的东西,那么你可以去接口。 但是,如果你也想为你的子类指定一些东西,你也想要你的类也应该有一些自己的方法。那么在那种情况下你可以去抽象类

答案 13 :(得分:0)

您无法使用抽象类实现多重继承,这就是Sun Microsystems提供接口的原因。

您不能扩展两个类,但可以实现多个接口。

答案 14 :(得分:0)

抽象类可以包含非抽象的方法,而在接口中,所有方法都是抽象的,必须实现。

当您知道将始终实现这些特定方法时,您应该使用接口。你也可以从多个接口继承,这是java处理多重继承的方式

答案 15 :(得分:0)

InterfaceAbstract Class是在OOP语言中实现抽象的两种不同方式。

接口提供100%抽象,即所有方法都是抽象的。

抽象类提供0 to 100%抽象,即它可能有或没有抽象方法。

当我们希望客户实现某种类型的所有功能时,我们可以使用Interface

Abstract Class实施者可以提供某些常用功能时,我们可以使用Abstract Class,客户将有机会实现他实际需要的功能。

答案 16 :(得分:0)

抽象类:当超类和子类之间存在强大的is-a关系时使用它,并且所有子类都有一些共同的行为。

接口:它只定义所有子类需要遵循的协议。

答案 17 :(得分:-1)

接口和抽象类似乎非常相似,但它们之间存在重要差异。

抽象基于良好的“ is-a ”关系。这意味着你会说汽车是本田汽车,本田汽车是汽车。在类上使用抽象意味着您也可以使用抽象方法。这将需要从中扩展的任何子类来获取抽象方法并覆盖它们。使用下面的例子,我们可以创建一个抽象的howToStart();需要每个类实现它的方法。

通过抽象,我们可以提供代码之间的相似性,因此我们仍然会有一个基类。使用Car类理念的一个例子,我们可以创建:

public abstract class Car{
    private String make;
    private String model

    protected Car() { }  // Default constructor

    protect Car(String make, String model){
        //Assign values to 
    }

    public abstract void howToStart();
}

然后在本田课上我们会:

public class Honda extends implements Engine {

    public Honda() { }  // Default constructor

    public Honda(String make, String model){
        //Assign values
    }

    @Override
    public static void howToStart(){
        // Code on how to start
    }

}

接口基于“has-a”关系。这意味着你可以说汽车有发动机,但发动机不是汽车。在上面的例子中,本田有implements Engine

对于引擎界面,我们可以创建:

public interface Engine {
    public void startup();
}

该接口将提供多对一实例。因此我们可以将引擎接口应用于任何类型的汽车。我们也可以将它扩展到其他对象。就像我们要制作一个船类,并且有船类的子类一样,我们可以扩展Engine并且让船的子类需要startup();方法。接口适用于为具有某些相似性的各种类创建框架。我们还可以在一个类中实现多个实例,例如:

public class Honda extends implements Engine, Transmission, List<Parts>

希望这有帮助。