接口和抽象类之间有什么区别?

时间:2009-12-16 08:15:16

标签: oop interface abstract-class

接口和抽象类之间究竟有什么区别?

38 个答案:

答案 0 :(得分:2128)

接口

界面是合同:编写界面的人说:“嘿,我接受那样的东西”,使用界面的人说“< em>好的,我写的课看起来就像“。

接口是空壳。只有方法的签名,这意味着方法没有正文。界面无能为力。这只是一种模式。

例如(伪代码):

// I say all motor vehicles should look like this:
interface MotorVehicle
{
    void run();

    int getFuel();
}

// My team mate complies and writes vehicle looking that way
class Car implements MotorVehicle
{

    int fuel;

    void run()
    {
        print("Wrroooooooom");
    }


    int getFuel()
    {
        return this.fuel;
    }
}

实现一个接口消耗很少的CPU,因为它不是一个类,只是一堆名称,因此没有任何昂贵的查找。它很重要,例如在嵌入式设备中。


抽象类

抽象类与接口不同,是类。它们的使用成本更高,因为当你继承它们时会有一个查找。

抽象类看起来很像接口,但它们还有更多东西:您可以为它们定义行为。更多的是关于一个人说,“这些类应该看起来像那样,并且他们有共同点,所以填补空白!”。

例如:

// I say all motor vehicles should look like this:
abstract class MotorVehicle
{

    int fuel;

    // They ALL have fuel, so lets implement this for everybody.
    int getFuel()
    {
         return this.fuel;
    }

    // That can be very different, force them to provide their
    // own implementation.
    abstract void run();
}

// My teammate complies and writes vehicle looking that way
class Car extends MotorVehicle
{
    void run()
    {
        print("Wrroooooooom");
    }
}

实施

虽然抽象类和接口应该是不同的概念,但实现使得该语句有时是不真实的。有时,它们甚至不是你认为的那样。

在Java中,强制执行此规则,而在PHP中,接口是没有声明方法的抽象类。

在Python中,抽象类更像是一种可以从ABC模块获得的编程技巧,实际上是使用元类,因此也就是类。接口与这种语言中的鸭子类型更相关,它是约定和调用描述符的特殊方法(__method__方法)之间的混合。

与编程一样,有另一种语言的理论,实践和实践: - )

答案 1 :(得分:825)

abstract classinterface之间的主要技术差异是:

  • 抽象类可以有常量,成员,方法存根(没有正文的方法)和已定义的方法,而接口只能有常量方法存根

  • 可以使用任何可见性定义抽象类的方法和成员,而接口的所有方法都必须定义为public(默认情况下它们是公共定义的)

  • 继承抽象类时,具体子类必须定义抽象方法,而抽象类可以扩展另一个抽象类和抽象方法。不必定义父类。

  • 同样,扩展另一个接口的接口不负责从父接口实现方法。这是因为接口无法定义任何实现。

  • 子类只能扩展单个类(抽象或具体),而接口可以扩展,或者类可以实现多个其他接口。 / p>

  • 子类可以使用相同或更少限制的可见性来定义抽象方法,而实现接口的类必须使用完全相同的可见性(公共)来定义方法。

答案 2 :(得分:129)

接口仅包含功能的定义/签名,如果我们有一些共同的功能以及常见的签名,那么我们需要使用抽象类。通过使用抽象类,我们可以同时提供行为和功能。继承抽象类的另一个开发人员可以轻松使用此功能,因为他们只需填写空白。

enter image description here 摘自:

http://www.dotnetbull.com/2011/11/difference-between-abstract-class-and.html

http://www.dotnetbull.com/2011/11/what-is-abstract-class-in-c-net.html http://www.dotnetbull.com/2011/11/what-is-interface-in-c-net.html

答案 3 :(得分:78)

可在此处找到解释:http://www.developer.com/lang/php/article.php/3604111/PHP-5-OOP-Interfaces-Abstract-Classes-and-the-Adapter-Pattern.htm

  

抽象类是一个类   仅由部分实施   程序员。它可能包含一个或多个   抽象方法。一种抽象的方法   只是一个函数定义   用来告诉程序员   方法必须在孩子身上实施   类。

     

接口类似于摘要   类;确实界面占据了   与类和抽象相同的命名空间   类。出于这个原因,你不能   定义具有相同名称的接口   作为一个班级。界面是完全的   抽象类;没有一种方法   是实现而不是一个类   据说可以从中进行分类   实现该接口。

无论如何,我发现接口的这种解释有点令人困惑。更常见的定义是:接口定义了实现类必须满足的契约。接口定义由公共成员的签名组成,没有任何实现代码。

答案 4 :(得分:37)

一些重要的差异:

以表格形式:

Difference

作为stated by Joe from javapapers

  

1.主要区别是Java接口的方法是隐式抽象的,不能实现。 Java抽象类可以   拥有实现默认行为的实例方法。

     

2.在Java接口中声明的变量默认为final。抽象类可能包含非最终变量。

     

3.默认情况下,Java接口的成员是公共的。 Java抽象类可以具有类似私有的类成员的通常风格,   受保护等。

     

4.Java接口应该使用关键字“implements”来实现;应使用关键字“extends”扩展Java抽象类。

     

5.An接口只能扩展另一个Java接口,抽象类可以扩展另一个Java类并实现多个Java   接口

     

6. Java类可以实现多个接口,但它只能扩展一个抽象类。

     

7.Interface是绝对抽象的,无法实例化; Java抽象类也无法实例化,但如果是,则可以调用   main()存在。

     

8.与java抽象类相比,java接口很慢,因为它需要额外的间接。

答案 5 :(得分:37)

我不想强调差异,这些差异已在许多答案中说过(关于接口中变量的公共静态最终修饰符以及对抽象类中受保护的私有方法的支持)

简单来说,我想说:

interface:通过多个不相关的对象实现合同

抽象类:在多个相关对象之间实现相同或不同的行为

来自Oracle documentation

如果符合以下情况,请考虑使用抽象类

  1. 您希望在几个密切相关的类之间共享代码。
  2. 您希望扩展抽象类的类具有许多常用方法或字段,或者需要除公共之外的访问修饰符(例如protected和private)。
  3. 您想要声明非静态或非最终字段。
  4. 在以下情况下考虑使用接口

    1. 您希望不相关的类会实现您的界面。例如,许多不相关的对象可以实现Serializable接口。
    2. 您希望指定特定数据类型的行为,但不关心谁实现其行为。
    3. 您希望利用类型的多重继承。
    4. 抽象类与具体类建立“是一种”关系。 interface为类提供“具有”功能。

      如果您正在寻找Java作为编程语言,可以参考以下内容:

      Java 8通过提供interface方法功能在一定程度上缩小了abstractdefault类之间的差距。 接口没有方法的实现现在不再有效。

      有关详细信息,请参阅此文档page

      请查看此SE问题,以便更好地理解代码示例。

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

答案 6 :(得分:29)

重点是:

  • 摘要是面向对象的。它提供了“对象”应具有的基本数据和/或应该能够执行的功能。它关注对象的基本特征:它有什么以及它可以做什么。因此,从同一抽象类继承的对象共享基本特征(泛化)。
  • 界面是面向功能的。它定义了对象应具有的功能。无论它是什么对象,只要它能够执行界面中定义的这些功能,就可以了。它忽略了其他一切。一个对象/类可以包含几个(一组)功能;因此,一个类可以实现多个接口。

答案 7 :(得分:24)

我正在建造一个300层的建筑物

该建筑的蓝图界面

  • 例如,Servlet(I)

建筑物最多可容纳200层 - 部分完成--- 抽象

  • 部分实现,例如,generic和HTTP servlet

建筑施工完成 - 具体

  • 完全实现,例如,自己的servlet

接口

  • 我们对实施,只是要求一无所知。我们可以 去寻找一个界面。
  • 默认情况下,每个方法都是公开的和抽象的
  • 这是一个100%纯粹的抽象类
  • 如果我们宣布公开,我们就不能申报私人和受保护的
  • 如果我们声明抽象,我们不能声明final,static,synchronized,strictfp和native
  • 每个界面都有公共,静态和最终
  • 序列化和瞬态不适用,因为我们无法在接口
  • 中创建实例
  • 非挥发性,因为它是最终的
  • 每个变量都是静态的
  • 当我们在接口内声明变量时,我们需要在声明
  • 时初始化变量
  • 不允许实例和静态阻止

摘要

  • 部分实施
  • 它有一个抽象的方法。另外,它使用具体的
  • 对抽象类方法修饰符没有限制
  • 对抽象类变量修饰符没有限制
  • 我们不能声明除抽象
  • 之外的其他修饰符
  • 初始化变量没有限制

取自DurgaJobs网站

答案 8 :(得分:23)

如果要在继承层次结构中提供多态行为,请使用抽象类。

当您想要完全不相关的类的多态行为时,请使用接口。

答案 9 :(得分:18)

让我们再次讨论这个问题:

让你知道的第一件事是1/1和1 * 1会产生相同的结果,但这并不意味着乘法和除法是相同的。显然,他们保持着良好的关系,但请注意,两者都是不同的。

我将指出主要的差异,其余的已经解释过:

抽象类对于建立类层次结构非常有用。乍一看任何要求,我们都清楚地知道要构建什么完全,但我们知道要构建什么。所以你的抽象类是你的基类。

接口对于让其他层次结构或类知道我能够做什么很有用。当你说我有能力时,你必须具备这种能力。接口将标记为类必须实现相同的功能。

答案 10 :(得分:13)

实际上非常简单。

您可以将接口视为一个类,只允许使用抽象方法而不允许其他方法。

因此,界面只能“声明”而不能定义您希望该类具有的行为。

抽象类允许您同时声明(使用抽象方法)以及定义(使用完整方法实现)您希望类具有的行为。

普通类只允许您定义,而不是声明您希望该类具有的行为/动作。

最后一件事,

在Java中,您可以实现多个接口,但只能扩展一个(抽象类或类)...

这意味着定义行为的继承被限制为仅允许每个类一个...即,如果您想要一个类来自A类,B类和C类的行为,则需要执行以下操作:A类扩展B,Class C扩展了A ..它有点关于多重继承的方式......

接口另一方面,您可以这样做:接口C实现A,B

所以实际上Java只在“声明的行为”即接口中支持多重继承,并且只支持具有已定义行为的单继承..除非你按照我描述的方式进行循环...

希望这是有道理的。

答案 11 :(得分:11)

接口与抽象类的比较是错误的。应该进行另外两个比较:1)界面与班级和2)抽象与最终班级

接口与类

接口是两个对象之间的契约。例如,我是邮递员,你是一个提供的套餐。我希望你知道你的送货地址。当有人给我一个包裹时,它必须知道它的送货地址:

interface Package {
  String address();
}

是一组遵守合同的对象。例如,我是“Box”组的一个盒子,我遵守邮递员要求的合同。与此同时,我遵守其他合同:

class Box implements Package, Property {
  @Override
  String address() {
    return "5th Street, New York, NY";
  }
  @Override
  Human owner() {
    // this method is part of another contract
  }
}

摘要与最终

抽象类是一组不完整的对象。他们不能使用,因为他们错过了一些部分。例如,我是一个抽象的GPS感知框 - 我知道如何检查我在地图上的位置:

abstract class GpsBox implements Package {
  @Override
  public abstract String address();
  protected Coordinates whereAmI() {
    // connect to GPS and return my current position
  }
}

这个类,如果由另一个类继承/扩展,可能非常有用。但它本身 - 它没用,因为它不能有物体。抽象类可以构建最终类的元素。

最终类是一组完整的对象,可以使用,但不能修改。他们确切知道如何工作和做什么。例如,我是一个总是到达其构造期间指定地址的Box:

final class DirectBox implements Package {
  private final String to;
  public DirectBox(String addr) {
    this.to = addr;
  }
  @Override
  public String address() {
    return this.to;
  }
}

在大多数语言中,如Java或C ++,可以使只是一个类,既不是抽象也不是最终。这样的类可以继承并可以实例化。但我并不认为这与面向对象的范式完全一致。

同样,将接口与抽象类进行比较是不正确的。

答案 12 :(得分:8)

唯一的区别是一个人可以参与多重继承,而其他人则不能。

接口的定义随着时间的推移而发生了变化。你认为一个接口只有方法声明而且只是合同吗?那么静态最终变量以及Java 8之后的默认定义呢?

接口被引入Java,因为the diamond problem具有多重继承,这就是他们实际打算做的事情。

接口是为了避免多重继承问题而创建的构造,可以包含抽象方法,默认定义和静态最终变量。

请参阅 Why does Java allow static final variables in interfaces when they are only intended to be contracts?

答案 13 :(得分:8)

简而言之,差异如下:

接口抽象类之间的语法差异:

  1. 抽象类的方法和成员可以具有任何可见性。 界面的所有方法都必须公开 //不再适用于Java 9
  2. Abstract 类的具体子类必须定义所有抽象方法。 抽象子类可以有抽象方法。扩展另一个接口的接口不需要为从父接口继承的方法提供默认实现。
  3. 子类只能扩展一个类。 接口可以扩展多个接口。一个类可以实现多个接口。
  4. 子类可以定义具有相同或更少限制性可见性的抽象方法,而实现接口的类必须将所有接口方法定义为public。
  5. 抽象类可以包含构造函数但不包含接口
  6. Java 9的接口具有私有静态方法。
  7. 现在在界面中:

    public static - 支持
    public abstract - 支持
    public default - 支持
    private static - 支持
    private abstract - 编译错误
    private default - 编译错误
    private - 支持

答案 14 :(得分:7)

界面:转动(向左转,向右转。)

抽象类:轮。

类:方向盘,源自Wheel,暴露界面转动

一个用于对可以在各种事物中提供的行为进行分类,另一个用于对事物本体进行建模。

答案 15 :(得分:6)

如果您有一些可供多个类使用的常用方法,请转到抽象类。 否则,如果您希望课程遵循一些明确的蓝图,请参阅接口。

以下示例说明了这一点。

Java中的抽象类:

abstract class animals
{
    // They all love to eat. So let's implement them for everybody
    void eat()
    {
        System.out.println("Eating...");
    }
    // The make different sounds. They will provide their own implementation.
    abstract void sound();
}

class dog extends animals
{
    void sound()
    {
        System.out.println("Woof Woof");
    }
}

class cat extends animals
{
    void sound()
    {
        System.out.println("Meoww");
    }
}

以下是Java中接口的实现:

interface Shape
{
    void display();
    double area();
}

class Rectangle implements Shape 
{
    int length, width;
    Rectangle(int length, int width)
    {
        this.length = length;
        this.width = width;
    }
    @Override
    public void display() 
    {
        System.out.println("****\n* *\n* *\n****"); 
    }
    @Override
    public double area() 
    {
        return (double)(length*width);
    }
} 

class Circle implements Shape 
{
    double pi = 3.14;
    int radius;
    Circle(int radius)
    {
        this.radius = radius;
    }
    @Override
    public void display() 
    {
        System.out.println("O"); // :P
    }
    @Override
    public double area() 
    { 
        return (double)((pi*radius*radius)/2);
    }
}

简而言之,一些重要的要点:

  1. Java界面中声明的变量默认为final。抽象类可以包含非最终变量。

  2. Java接口中声明的变量默认为static。抽象类可以有非静态变量。

  3. 默认情况下,Java接口的成员是公共的。 Java抽象类可以具有通常的类成员类型,如private,protected等。

答案 16 :(得分:4)

不是原始问题的答案,但是一旦你得到它们之间的差异的答案,你将进入使用时 - 每个困境: When to use interfaces or abstract classes? When to use both?

我对OOP的了解有限,但是看到界面作为语法形容词的等价物直到现在都适用于我(如果这种方法是伪造的,请纠正我!)。例如,接口名称就像您可以为类提供的属性或功能,并且类可以包含许多类:ISerializable,ICountable,IList,ICacheable,IHappy,...

答案 17 :(得分:3)

总结最简单的方法是interface

  1. 完全抽象,除了defaultstatic方法之外;虽然它有defaultstatic方法的定义(方法签名+实现),但它只有其他方法的声明(方法签名)。
  2. 遵守比规则更宽松的规则(一个类可以实现多个interface,而interface可以从多个interface继承。所有变量都是隐式常量,无论是否指定为public static final。所有成员都隐含public,无论是否指定。
  3. 通常用于保证实现类具有指定的功能和/或与实现相同接口的任何其他类兼容。
  4. 同时,abstract类是:

    1. 从完全抽象到完全实现的任何地方,倾向于拥有一个或多个abstract方法。可以包含声明和定义,声明标记为abstract
    2. 一个完整的类,并且遵守管理其他类的规则(只能从一个类继承),条件是它不能被实例化(因为它不能保证它的实例化)完全实施)。可以有非常量成员变量。可以实现成员访问控制,将成员限制为protectedprivate或私有包(未指定)。
    3. 通常用于提供尽可能多的子类共享的实现,或者提供程序员能够提供的尽可能多的实现。
    4. 或者,如果我们想将其全部归结为一句话:interface是实现类具有,但是abstract类是子类的内容

答案 18 :(得分:3)

您可以在界面抽象类之间找到明显的区别。

<强>接口

  • 界面只包含抽象方法。
  • 强制用户在实现界面时实现所有方法。
  • 仅包含最终和静态变量。
  • 使用interface关键字声明。
  • 接口的所有方法都必须定义为public。
  • 接口可以扩展,或者类可以实现多个其他接口 接口。

抽象类

  • 抽象类包含抽象和非抽象方法。

  • 继承时不强制用户实现所有方法 抽象类。

  • 包含各种变量,包括原始和非原始

  • 使用abstract keyword声明。

  • 抽象类的方法和成员可以用any定义 可视性。

  • 子类只能扩展一个类(抽象或具体)。

答案 19 :(得分:3)

代表实际实现的抽象类和接口之间的差异。

接口:它是一个关键字,它用于定义对象的模板或蓝图,它强制所有子类都遵循相同的原型,与实现一样,所有子类可以根据需要自由实现功能。

我们应该使用接口的一些其他用例。

两个外部对象之间的通信(我们的应用程序中的第三方集成)通过接口完成此处接口作为合同。

抽象类:抽象,它是一个关键字,当我们在任何类之前使用这个关键字然后它变成抽象类。它主要用于我们需要定义模板以及一些默认所有子类后面的对象的功能,这样就删除了冗余代码和我们可以使用抽象类的另一个用例,比如我们希望没有其他类可以直接实例化该类的对象,只有派生类才能使用该功能。

抽象类的示例:

{'name': {u'value': u'Name of object'},
 'sid': {u'value': 110}}

界面示例:

 public abstract class DesireCar
  {

 //It is an abstract method that defines the prototype.
     public abstract void Color();

  // It is a default implementation of a Wheel method as all the desire cars have the same no. of wheels.   
 // and hence no need to define this in all the sub classes in this way it saves the code duplicasy     

  public void Wheel() {          

               Console.WriteLine("Car has four wheel");
                }
           }


    **Here is the sub classes:**

     public class DesireCar1 : DesireCar
        {
            public override void Color()
            {
                Console.WriteLine("This is a red color Desire car");
            }
        }

        public class DesireCar2 : DesireCar
        {
            public override void Color()
            {
                Console.WriteLine("This is a red white Desire car");
            }
        }

答案 20 :(得分:3)

为了给出一个简单但明确的答案,它有助于设置上下文:当你不想提供完整的实现时,你可以使用它们。

主要区别在于接口根本没有实现(只有没有主体的方法),而抽象类也可以有成员和方法,也可以部分实现。

答案 21 :(得分:3)

我想再增加一个有意义的差异。 例如,您有一个包含数千行代码的框架。现在,如果要使用方法enhanceUI()在整个代码中添加新功能,那么最好在抽象类中添加该方法,而不是在接口中添加。因为,如果你在一个接口中添加这个方法,那么你应该在所有实现的类中实现它,但如果你在抽象类中添加方法则不是这样。

答案 22 :(得分:3)

根据定义,接口不能具有任何方法的实现,并且无法初始化成员变量。

但是,抽象类可以实现方法并初始化成员变量。

如果您希望更改合同,请使用抽象类,即,将来您可能需要添加新方法。

在这种情况下,如果您决定使用界面,当界面更改为包含界面时,您的应用程序将在您转储新界面dll时中断。

要详细阅读,请访问difference between abstract class and a interface

答案 23 :(得分:3)

要点:

  • 抽象类可以有属性,数据字段,方法(完整/ 两个都不完整。
  • 如果方法或属性在abstract关键字中定义,必须在派生类中重写。(它的工作方式是紧密耦合 功能)
  • 如果为抽象类中的方法或属性定义抽象关键字,则无法定义方法体和获取/设置值 属性,必须在派生类中重写。
  • 抽象类不支持多重继承。
  • 抽象类包含构造函数。
  • 抽象类可以包含subs,functions,properties的访问修饰符。
  • 只有抽象类的完整成员可以是静态。
  • 接口只能从另一个接口继承,不能从抽象类继承,抽象类可以从另一个抽象类或其他接口继承。

优势:

  • 这是一种强制所有子类进行相同层次结构或标准的契约。
  • 如果各种实现具有相同的类型并使用常见的行为或状态,则最好使用抽象类。
  • 如果我们向抽象类添加一个新方法,那么我们可以选择提供默认实现,因此所有现有代码都可以正常工作。
  • 它允许快速执行而不是接口。(接口需要更多时间在相应的类中查找实际方法。)
  • 它可以用于紧密松散的耦合。

在此处查找详细信息 http://pradeepatkari.wordpress.com/2014/11/20/interface-and-abstract-class-in-c-oops/

答案 24 :(得分:3)

继承用于两个目的:

  • 允许对象将父类型数据成员和方法实现视为自己的。

  • 允许对需要引用超类型对象的代码使用一种类型的对象的引用。

在支持广义多重继承的语言/框架中,通常很少需要将类型分类为“接口”或“抽象类”。但是,流行的语言和框架将允许类型将另一个类型的数据成员或方法实现视为自己的类型,即使它们允许类型可以替代任意数量的其他类型。

抽象类可能包含数据成员和方法实现,但只能由不从任何其他类继承的类继承。接口对实现它们的类型几乎没有限制,但不能包含任何数据成员或方法实现。

有时,类型可以替代许多不同的东西;还有一些时候,对象将父类型数据成员和方法实现视为自己的有用。区分接口和抽象类允许在最相关的情况下使用这些能力。

答案 25 :(得分:2)

抽象类是无法创建对象的类或无法实例化的类。 抽象方法使类抽象。 需要继承抽象类以覆盖抽象类中声明的方法。 访问说明符没有限制。 抽象类可以有构造函数和其他具体(非abstarct方法)方法,但接口不能有。

接口是方法的蓝图/模板。(例如,纸上的房子被给出(接口室),不同的建筑师将使用他们的想法来构建它(实现房屋界面的建筑师类)。 它是抽象方法,默认方法,静态方法,最终变量和嵌套类的集合。 所有成员将是最终成员或公共成员,不允许使用受保护和私有访问说明符。不允许创建对象。 必须创建一个类才能使用实现接口,并且还要覆盖接口中声明的抽象方法。接口是松耦合的一个很好的例子(动态多态/动态绑定) 接口实现了多态性和抽象。它告诉我们该做什么但是如何做是由实现类定义的。 对于Eg。有一家汽车公司,它希望它所制造的所有汽车的某些功能都是相同的,因此该公司将制造具有这些功能和不同类别汽车的接口车(如Maruti Suzkhi,Maruti 800)将覆盖这些功能(功能)。

为什么我们已经有抽象类的界面? Java仅支持多级和层级继承,但在接口的帮助下,我们可以实现多重继承。

答案 26 :(得分:2)

许多初级开发人员错误地认为接口,抽象和具体类是同一事物的微小变化,并且纯粹基于技术理由选择其中一个:我是否需要多重继承?我需要一些地方来放置常用方法吗?我是否需要打扰除了具体课程以外的其他内容?这是错误的,隐藏在这些问题中的主要问题是:&#34;我&#34; 。当您自己编写代码时,您很少会想到其他现有或未来的开发人员在使用代码或使用代码。

接口和抽象类虽然从技术角度来看显然相似,却具有完全不同的含义和目的。

摘要

  1. 界面定义合约,某些实施将为您实现

  2. 抽象类提供您的实现可以重复使用的默认行为

  3. 替代摘要

    1. 用于定义公共API的接口
    2. 抽象类供内部使用,用于定义SPI
    3. 关于隐藏实现细节的重要性

      具体课程以非常具体的方式完成实际工作。例如,ArrayList使用连续的内存区域以紧凑的方式存储对象列表,提供快速随机访问,迭代和就地更改,但在插入,删除和偶尔偶数时很糟糕增加;同时,LinkedList使用双链节点来存储对象列表,而不是提供快速迭代,就地更改和插入/删除/添加,但随机访问非常糟糕。这两种类型的列表针对不同的用例进行了优化,对您将如何使用它们非常重要。如果您试图将性能从与您进行大量交互的列表中挤出来,并且在选择列表类型时由您决定,那么您应该仔细选择要实例化的列表。< / p>

      另一方面,列表的高级用户并不真正关心它的实际实现方式,他们应该与这些细节隔离开来。让我们想象Java没有公开List接口,但只有一个具体的List类实际上是LinkedList现在正是什么。所有Java开发人员都会根据实现细节定制他们的代码:避免随机访问,添加缓存以加快访问速度,或者只是自己重新实现ArrayList,尽管它实际上与所有其他代码不兼容仅适用于List。那将是可怕的...但现在想象一下,Java大师实际上意识到链接列表对于大多数实际用例来说是可怕的,并且决定切换到他们唯一可用的List类的数组列表。这会影响世界上每个Java程序的性能,人们也不会为此感到高兴。主要的罪魁祸首是实施细节可用,开发人员认为这些细节是他们可以依赖的永久合同。这就是为什么隐藏实现细节非常重要,并且只定义抽象契约。这是接口的目的:定义一个方法接受什么样的输入,以及期望什么样的输出,而不暴露所有会诱使程序员调整他们的代码以适应可能随任何未来更新而改变的内部细节的内容

      抽象类位于接口和具体类之间。它应该有助于实现共享共同或无聊的代码。例如,AbstractCollection根据大小为0 isEmpty提供基本实现,contains为迭代并进行比较,addAll为重复add,依此类推。这使实现可以专注于区分它们的关键部分:如何实际存储和检索数据。

      API与SPI

      接口是代码的不同部分之间的低内聚网关。它们允许库存在和发展,而不会在内部发生变化时破坏每个库用户。它被称为应用程序编程接口 ,而不是应用程序编程类。在较小的规模上,它们还允许多个开发人员通过良好记录的界面分离不同的模块,从而在大型项目上成功协作。

      抽象类是实现接口时使用的高内聚帮助程序,假定某些级别的实现细节。或者,抽象类用于定义SPI,服务提供者接口。

      API和SPI之间的区别很微妙,但很重要:对于API,重点是谁使用,对于SPI,重点是谁实现< / strong>它。

      向API添加方法很简单,API的所有现有用户仍将进行编译。向SPI添加方法很难,因为每个服务提供者(具体实现)都必须实现新方法。如果接口用于定义SPI,则提供者必须在SPI合同发生变化时发布新版本。如果使用抽象类,则可以根据现有抽象方法定义新方法,也可以将其作为空throw not implemented exception存根定义,这至少允许旧版本的服务实现仍然可以编译和运行。

      关于Java 8和默认方法的说明

      尽管Java 8引入了接口的默认方法,这使得接口和抽象类之间的界限更加模糊,但这并不是为了使实现可以重用代码,而是为了更容易地更改同时用作接口的接口。 API和SPI(或错误地用于定义SPI而不是抽象类)。

      使用哪一个?

      1. 代码的其他部分或其他外部代码 公开使用吗?添加一个接口以隐藏公共抽象合同中的实现细节,这是该事物的一般行为。
      2. 的东西是什么东西应该有多个实现,有很多共同的代码?同时创建一个接口和一个抽象的,不完整的实现。
      3. 是否只有一个实现,没有其他人会使用它?把它变成一个具体的课程。
        1. &#34;以往&#34;很长一段时间,你可以安全地玩它,并在它上面添加一个界面。
      4. 一个必然结果:反过来常常做错了:当使用 thing 时,总是尝试使用你真正需要的最通用的类​​/接口。换句话说,不要将变量声明为ArrayList theList = new ArrayList(),除非您实际上非常依赖它作为数组列表,并且没有其他类型的列表会将其删除为了你。如果它是一个列表,而不是任何其他类型的集合实际上并不重要,请使用List theList = new ArrayList代替Collection theCollection = new ArrayList,甚至{{1}}。

答案 27 :(得分:2)

我晚了10年,但是想尝试任何方法。几天前在中等水平上写了差不多的帖子。想在这里发布。

tl; dr;当您看到“是A”关系时,请使用继承/抽象类。当您看到“具有”关系时,请创建成员变量。当您看到“依赖外部提供程序”实现(而不是继承)接口时。

面试问题:接口和抽象类之间有什么区别?以及您如何决定何时使用什么? 我基本上会得到以下一个或所有答案: 答案1:您不能创建抽象类和接口的对象。

ZK (这是我的姓名缩写):您无法创建任何一个的对象。所以这没什么区别。这是接口和抽象类之间的相似之处。计数器 问题:为什么您不能创建抽象类或接口的对象?

答案2:抽象类可以具有部分或默认实现的函数体。

ZK:反问:因此,如果将其更改为纯抽象类,则将所有虚拟函数标记为抽象,并且不为任何虚拟函数提供默认实现。这样会使抽象类和接口相同吗?在那之后可以互换使用吗?

答案3:接口允许多重继承,而抽象类则不允许。

ZK:反问题:您真的从接口继承吗?还是只实现一个接口,并从抽象类继承?实施和继承有什么区别? 这些反问使候选人脱颖而出,使他们大为挠头,或者只是转到下一个问题。这使我认为人们需要这些面向对象编程的基本构建模块的帮助。 原始问题和所有反问题的答案均​​以英语和UML找到。 您必须至少了解以下内容才能更好地理解这两种构造。

共同名词:共同名词是对同一类别或同类事物“共同”使用的名称。例如水果,动物,城市,汽车等。

专有名词:专有名词是物体,地点或事物的名称。苹果,猫,纽约,本田雅阁等。

汽车是一个普通名词。本田雅阁是一个专有名词,可能是一个合成专有名词,这是一个由两个名词组成的专有名词。

来到UML部分。您应该熟悉以下关系:

  • 是A
  • 有A
  • 使用

让我们考虑以下两个句子。 -本田雅阁是汽车吗? -本田雅阁有车吗?

哪个听起来正确?普通英语和理解能力。本田雅阁和汽车共享“是”关系。本田雅阁没有汽车。这是辆车。本田雅阁“里面有一个”音乐播放器。

当两个实体共享“是”关系时,则更适合继承。并且具有关系是创建成员变量的更好的选择。 建立好之后,我们的代码如下:

abstract class Car
{
   string color;
   int speed;
}
class HondaAccord : Car
{
   MusicPlayer musicPlayer;
}

现在,本田不生产音乐播放器。或至少不是他们的主要业务。

因此,他们与其他公司联系并签订了合同。如果您在此处接通电源,并且这两根线上的输出信号都可以在这些扬声器上正常播放。

这使Music Player成为界面的理想选择。只要连接正常,您就不必在乎谁提供支持。

您可以用Sony或其他方法替换LG的MusicPlayer。而且它不会改变本田雅阁的情况。

为什么不能创建抽象类的对象?

因为您不能走进陈列室说要给我一辆车。您必须提供一个专有名词。什么车?可能是本田雅阁。那是一个销售代理可以为您带来收益的时候。

为什么不能创建界面对象? 因为您不能走进陈列室,说给我音乐播放器的合同。这不会有帮助。消费者和提供者之间的接口只是为了促进协议。您将如何使用协议副本?它不会播放音乐。

为什么接口允许多重继承?

接口不被继承。接口已实现。 该界面是与外界互动的候选者。 本田雅阁有一个加油接口。它具有用于轮胎充气的接口。还有用于给足球充气的软管。因此,新代码如下所示:

abstract class Car
{
    string color;
    int speed;
}
class HondaAccord : Car, IInflateAir, IRefueling
{
    MusicPlayer musicPlayer;
}

英语将这样写:“本田雅阁是支持充气和加油的汽车”。

答案 28 :(得分:1)

在接口中,所有方法必须只是定义,而不是单个应该实现。

但是在抽象类中必须有一个只有定义的抽象方法,但是其他方法也可以在抽象类中实现...

答案 29 :(得分:1)

php.net上的抽象类和接口的简单而有效的解释:

  

接口就像一个协议。它不指定对象的行为;它指定代码如何告诉该对象采取行动。接口类似于英语:定义接口定义了代码如何与实现该接口的任何对象进行通信。

     

接口始终是协议或承诺。当一个类说“我实现接口Y”时,它说“我保证有任何与接口Y有对象的公共方法”。

     

另一方面,抽象类就像是一个部分构建的类。它就像一个填空的文件。它可能是使用英语,但这并不像某些文件已经写好的那样重要。

     

抽象类是另一个对象的基础。当一个类说“我扩展抽象类Y”时,它说“我使用了一个已经在另一个名为Y的类中定义的方法或属性”。

     

因此,请考虑以下PHP:

<?php
class X implements Y { } // this is saying that "X" agrees to speak language "Y" with your code.

class X extends Y { } // this is saying that "X" is going to complete the partial class "Y".
?>
     

如果您要分发其他人使用的类,您的类将实现特定的接口。该界面是为您的班级提供一组特定公共方法的协议。

     

如果您(或其他人)编写了一个已经编写了一些您希望在新类中使用的方法的类,那么您的类将扩展一个抽象类。

     

这些概念虽然容易混淆,但却截然不同且截然不同。出于所有意图和目的,如果您是任何类的唯一用户,则不需要实现接口。

答案 30 :(得分:1)

通常,Abstract类用于某些内容的核心,但接口用于附加外围设备。

当要为车辆创建基本类型时,应使用抽象类,但如果要添加不属于车辆基本概念的某些功能或属性,则应使用接口,例如,要添加“ ToJSON( )”功能。

接口具有广泛的抽象范围,而不是抽象类。 您可以在传递参数时看到这一点。请看以下示例:

enter image description here

如果将车辆用作参数,则只能使用其派生类型之一(公交车或汽车相同类别,仅是车辆类别)。 但是当您使用IMoveable接口作为参数时,您会有更多选择。

答案 31 :(得分:1)

在实用性方面(JAVA),抽象类和接口之间的主要区别是 抽象类可以保持状态。 除了保持状态之外,我们还可以使用Interface来实现rest操作。

答案 32 :(得分:1)

抽象类与接口的主题主要是关于语义的。

抽象类在不同的编程语言中通常是接口的超集,除了一件事之外,也就是说,您可以实现多个接口,但只能继承一个类。

一个界面定义了必须要做的事情;就像合同一样,但没有提供合同的实现。

抽象类定义什么是,并且通常托管子类之间的共享代码。

例如,Formatter应该能够format()。描述类似内容的常见语义是创建一个接口IFormatter,其声明为format(),其作用类似于合同。但是IFormatter并没有描述什么是什么,而是描述了它应该能够做到的。描述什么实际上是什么的通用语义是创建一个类。在这种情况下,我们将创建一个抽象类...因此,我们将创建一个实现该接口的抽象类Formatter。那是一个非常具有描述性的代码,因为我们现在知道我们有一个Formatter,并且现在我们知道每个Formatter都必须具备的功能。

一个非常重要的主题是文档(至少对于某些人来说...)。在您的文档中,您可能想要解释子类中的Formatter实际上是什么。拥有一个抽象类Formatter非常方便,您可以在子类中将文档链接到该抽象类。这是非常方便且通用的。另一方面,如果您没有抽象类Formatter而只有一个接口IFormatter,则必须在每个子类中解释实际上是Formatter的含义,因为接口是合同,并且您不会在接口文档中描述Formatter的实际含义–至少这不是常见的操作,并且您会破坏大多数开发人员认为正确的语义。

注意:使抽象类实现接口是一种非常常见的模式。

答案 33 :(得分:0)

Interfaces are generally the classes without logic just a signature. Whereas abstract classes are those having logic. Both support contract as interface all method should be implemented in the child class but in abstract only the abstract method should be implemented. When to use interface and when to abstract? Why use Interface?

class Circle {

protected $radius;

public function __construct($radius)

{
    $this->radius = $radius
}

public function area()
{
    return 3.14159 * pow(2,$this->radius); // simply pie.r2 (square);
}

}

//Our area calculator class would look like

class Areacalculator {

$protected $circle;

public function __construct(Circle $circle)
{
    $this->circle = $circle;
}

public function areaCalculate()
{
    return $circle->area(); //returns the circle area now
}

}

We would simply do

$areacalculator = new Areacalculator(new Circle(7)); 

Few days later we would need the area of rectangle, Square, Quadrilateral and so on. If so do we have to change the code every time and check if the instance is of square or circle or rectangle? Now what OCP says is CODE TO AN INTERFACE NOT AN IMPLEMENTATION. Solution would be:

Interface Shape {

public function area(); //Defining contract for the classes

}

Class Square implements Shape {

$protected length;

public function __construct($length) {
    //settter for length like we did on circle class
}

public function area()
{
    //return l square for area of square
}

Class Rectangle implements Shape {

$protected length;
$protected breath;

public function __construct($length,$breath) {
    //settter for length, breath like we did on circle,square class
}

public function area()
{
    //return l*b for area of rectangle
}

}

Now for area calculator

class Areacalculator {

$protected $shape;

public function __construct(Shape $shape)
{
    $this->shape = $shape;
}

public function areaCalculate()
{
    return $shape->area(); //returns the circle area now
}

}

$areacalculator = new Areacalculator(new Square(1));
$areacalculator->areaCalculate();

$areacalculator = new Areacalculator(new Rectangle(1,2));
$areacalculator->;areaCalculate();

Isn't that more flexible? If we would code without interface we would check the instance for each shape redundant code.

Now when to use abstract?

Abstract Animal {

public function breathe(){

//all animals breathe inhaling o2 and exhaling co2

}

public function hungry() {

//every animals do feel hungry 

}

abstract function communicate(); 
// different communication style some bark, some meow, human talks etc

}

Now abstract should be used when one doesn't need instance of that class, having similar logic, having need for the contract.

答案 34 :(得分:0)

enter image description here

这是对界面与抽象类的非常基本的理解。

答案 35 :(得分:0)

抽象类和iterfaces的一般概念是由其他类(不能单独构造)扩展/实现,这些类使用这些通用的&#34;设置&#34; (某种模板),使得为以后扩展它的所有对象设置特定通用行为变得简单。

抽象类具有常规方法集和抽象方法。扩展类在由抽象类扩展后可以包括未设置的方法。设置抽象方法时 - 它们是由稍后扩展它的类定义的。

接口具有与抽象类相同的属性,但仅包含抽象方法,可以在其他类中实现(并且可以实现多个接口),这将创建一个更永久固定的定义方法/静态变量。与抽象类不同,您无法添加自定义&#34;常规&#34;方法。

答案 36 :(得分:0)

接口和抽象类之间存在各种结构/语法上的差异。还有更多区别

[1] 基于方案的差异

当我们希望限制用户创建父类的对象并且我们相信将来会添加更多的抽象方法时,将使用抽象类。

当我们确定没有更多的抽象方法可以使用时,必须使用接口。然后只发布一个接口。

[2] 概念差异

如果是,则“将来是否需要提供更多抽象方法”,如果否,则将其作为接口。

(最合适且在Java 1.7之前有效)

答案 37 :(得分:0)

之所以称为接口,是因为它为由某个类实现的调用方(例如COM客户端)提供了方法的接口。通过将对象指针多态转换为实现的接口类型,它限制了对象对实现的接口功能的访问,该功能与同类可能实现的其他COM接口分开。客户端不需要知道哪个类实现了接口或该类中存在哪些其他方法。对象以它所知道的接口的形式呈现,并且仅通过在接口实例上调用接口的方法来使用该接口。

接口是所有方法都是虚拟的和抽象的(抽象在C ++中被称为纯虚拟;所有抽象方法都包含虚拟的说明符,因此是虚拟的)。抽象类是其中至少一种方法是虚拟的,并被指定为抽象的(或在C ++中为纯虚拟)。其他细节因语言而异。所有接口变量在Java中都是隐式public static final,但在C ++中不是。 Java允许抽象类中使用非静态属性,但是C ++允许两者都使用它们。