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


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

抽象类是一个仅部分由程序员它可能包含一个或多个抽象方法。抽象方法只是一个函数定义用于告诉程序员方法必须在子级中实现班接口类似于抽象班实际上,接口占据了与类和抽象名称空间相同类。因此,您不能定义具有相同名称的接口作为一个班级。接口是一个完整的抽象类;没有一种方法实现,而不是类从中派生出来,据说实现该接口。

无论如何,我觉得这个接口的解释有些混乱。更常见的定义是:接口定义实现类必须履行的契约。接口定义由公共成员的签名组成,没有任何实现代码。


接口

接口是一个契约:编写接口的人说,“嘿,我接受这样的东西”,而使用接口的人则说“好的,我编写的类是这样的”。

接口是一个空壳。只有方法的签名,这意味着方法没有主体。接口无法执行任何操作。这只是一种模式。

例如(伪代码):

// 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模块中获得,并且实际上使用元类,因此使用类。接口与这种语言中的duck类型更为相关,它混合了约定和调用描述符的特殊方法(__method__方法)。

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


实际上并不是最初问题的答案,但一旦你找到了它们之间的区别的答案,你就会进入何时使用每一个困境:何时使用接口或抽象类?何时同时使用两者?

我对OOP的了解有限,但将接口视为语法中形容词的等价物对我来说一直有效(如果这个方法是假的,请纠正我!)。例如,接口名称类似于可以赋予类的属性或功能,并且类可以具有许多属性或功能:ISerializable、ICountable、IList、ICacheable、IHappy。。。


抽象类和接口之间的关键技术差异是:

抽象类可以有常量、成员、方法存根(没有主体的方法)和定义的方法,而接口只能有常量和方法存根。抽象类的方法和成员可以以任何可见性定义,而接口的所有方法都必须定义为public(默认情况下定义为public)。继承抽象类时,具体的子类必须定义抽象方法,而抽象类可以扩展另一个抽象类,父类的抽象方法不必定义。类似地,扩展另一个接口的接口不负责从父接口实现方法。这是因为接口不能定义任何实现。子类只能扩展一个类(抽象或具体),而接口可以扩展或类可以实现多个其他接口。子类可以定义具有相同或更少限制性可见性的抽象方法,而实现接口的类必须定义具有完全相同可见性(公共)的方法。


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

首先要告诉你的是,1/1和1*1的结果是相同的,但这并不意味着乘法和除法是相同的。显然,他们有着良好的关系,但请注意,你们两个都不同。

我将指出主要的区别,其余的已经解释过了:

抽象类对于建模类层次结构非常有用。乍一看任何需求,我们都部分清楚要构建什么,但我们知道要构建什么。所以抽象类就是基类。

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


当您想在继承层次结构中提供多态行为时,请使用抽象类。

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


一些重要的区别:

以表格的形式:

正如Joe在javapapers中所说:

1.主要区别在于Java接口的方法是隐式抽象的,不能有实现。Java抽象类可以具有实现默认行为的实例方法。2.Java接口中声明的变量默认为final。抽象类可以包含非最终变量。3.默认情况下,Java接口的成员是公共的。Java抽象类可以具有类成员的通常风格,受保护等。。4.Java接口应使用关键字“implements”实现;Java抽象类应该使用关键字“extends”进行扩展。5.接口只能扩展另一个Java接口,抽象类可以扩展另一Java类并实现多个Java接口。6.Java类可以实现多个接口,但只能扩展一个抽象类。7.接口是绝对抽象的,不能实例化;Java抽象类也不能实例化,但如果main()存在。8.与java抽象类相比,java接口速度较慢,因为它需要额外的间接寻址。


在一个接口中,所有方法都只能是定义,而不能实现单个方法。

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


继承用于两个目的:

允许对象将父类型数据成员和方法实现视为自己的。允许期望引用超类型对象的代码使用对一种类型对象的引用。

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

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

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


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

摘自:

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.htmlhttp://www.dotnetbull.com/2011/11/what-is-interface-in-c-net.html


我正在建造一座300层的大楼

建筑的蓝图界面

例如,Servlet(I)

建筑高达200层-部分完工-摘要

部分实现,例如泛型和HTTPservlet

建筑施工完成混凝土

完整实现,例如,自己的servlet

界面

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

摘要

部分实施它有一个抽象的方法。此外,它使用混凝土对抽象类方法修饰符没有限制抽象类变量修饰符没有限制除了abstract,我们不能声明其他修饰符初始化变量没有限制

摘自DurgaJobs网站


其实很简单。

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

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

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

常规类只允许您定义而不是声明您希望类具有的行为/动作。

最后一件事,

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

这意味着定义行为的继承被限制为每个类只允许一个。。。例如,如果你想要一个从类a、B和C中封装行为的类,你需要执行以下操作:类a扩展B,类C扩展a。。这是一个有点迂回的方式来拥有多重继承。。。

另一方面,您可以简单地执行接口:接口C实现A、B

因此实际上,Java只在“声明的行为”(即接口)中支持多重继承,并且只支持具有定义行为的单一继承。。除非你像我描述的那样。。。

希望这是合理的。


接口与抽象类的比较是错误的。应该有另外两个比较:1)接口与类,2)抽象与最终类。

接口与类

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

interface Package {
  String address();
}

类是一组遵守契约的对象。例如,我是“箱子”小组的一名箱子,我遵守邮递员要求的合同。同时,我遵守其他合同:

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
  }
}

这个类如果被另一个类继承/扩展,可能非常有用。但就其本身而言,它是无用的,因为它不能有对象。抽象类可以是最终类的构建元素。

Final类是一组完整的对象,可以使用,但不能修改。他们确切地知道如何工作和做什么。例如,我是一个盒子,它总是在构建过程中到达指定的地址:

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++,可能只有一个类,既不是抽象类也不是最终类。这样的类可以继承并实例化。不过,我认为这并不严格符合面向对象的范例。

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


唯一的区别是一个可以参与多重继承,另一个不能。

接口的定义随着时间的推移而改变。你认为一个接口只有方法声明,只是契约吗?Java 8之后的静态最终变量和默认定义呢?

由于多重继承的菱形问题,接口被引入到Java中,而这正是它们真正想要做的。

接口是为解决多重继承问题而创建的构造,可以具有抽象方法、默认定义和静态最终变量。

请参阅为什么Java只允许在接口中使用静态最终变量,而这些变量仅用于契约?。


要点是:

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


要点:

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

优势:

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

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


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

简单地说,我想说:

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

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

来自Oracle文档

如果出现以下情况,请考虑使用抽象类:

您希望在几个密切相关的类之间共享代码。您希望扩展抽象类的类具有许多公共方法或字段,或者需要公共以外的访问修饰符(如protected和private)。您要声明非静态或非final字段。

如果出现以下情况,请考虑使用接口:

您希望不相关的类实现您的接口。例如,许多不相关的对象可以实现Serializable接口。您希望指定特定数据类型的行为,但不关心谁实现了它的行为。您希望利用类型的多重继承。

抽象类与具体类建立“是”关系。接口为类提供了“具有”功能。

如果您正在寻找Java作为编程语言,这里还有一些更新:

Java8通过提供默认方法特性,在一定程度上缩小了接口类和抽象类之间的差距。接口没有实现。方法现在不再有效。

有关详细信息,请参阅本文档页。

看看这个SE问题,了解代码示例,以便更好地理解。

我应该如何解释接口和抽象类之间的区别?


这里是对接口与抽象类的一个非常基本的理解。


总结起来最简单的方法是:

完全抽象,除了默认和静态方法;虽然它有默认和静态方法的定义(方法签名+实现),但它只有其他方法的声明(方法签名)。受比类更宽松的规则约束(类可以实现多个接口,接口可以从多个接口继承)。所有变量都是隐式常量,无论是否指定为公共静态final。所有成员都是隐式公共的,无论是否指定为公共成员。通常用于保证实现类将具有指定的特性和/或与实现相同接口的任何其他类兼容。

同时,抽象类是:

从完全抽象到完全实现,具有一个或多个抽象方法的倾向。可以包含声明和定义,声明标记为抽象。一个完整的类,并且受制于管理其他类的规则(只能从一个类继承),条件是它不能实例化(因为不能保证它完全实现)。可以具有非常量成员变量。可以实现成员访问控制,将成员限制为受保护、私有或私有包(未指定)。通常用于提供可由多个子类共享的尽可能多的实现,或者提供程序员能够提供的尽可能的实现。

或者,如果我们想将其归结为一句话:接口是实现类所拥有的,而抽象类是子类所拥有。


接口通常是没有逻辑的类,只有签名。而抽象类是具有逻辑的类。两者都支持作为接口的契约,所有方法都应该在子类中实现,但在抽象中只应该实现抽象方法。何时使用接口,何时抽象?为什么使用界面?

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
}

}

我们只需要

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

几天后,我们将需要矩形、正方形、四边形等区域。如果是这样,我们是否必须每次更改代码并检查实例是正方形、圆形还是矩形?现在OCP所说的是接口代码而不是实现。解决方案是:

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
}

}

现在是面积计算器

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();

这不是更灵活吗?如果我们在没有接口的情况下进行编码,我们将检查每个形状冗余代码的实例。

现在什么时候使用抽象?

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

}

现在,当一个人不需要那个类的实例,具有类似的逻辑,需要契约时,应该使用抽象。


许多初级开发人员错误地将接口、抽象类和具体类视为同一事物的细微变化,并纯粹基于技术原因选择其中之一:我需要多重继承吗?我需要一些地方来放置常用方法吗?除了一堂具体的课,我还需要为别的事情而烦恼吗?这是错误的,隐藏在这些问题中的是主要问题:“我”。当你自己编写代码时,你很少想到其他现在或将来的开发人员正在处理或使用你的代码。

接口和抽象类,虽然从技术角度看很相似,但有着完全不同的含义和目的。

总结

接口定义了某个实现将为您实现的契约。抽象类提供了您的实现可以重用的默认行为。

备选摘要

接口用于定义公共API抽象类用于内部使用和定义SPIs

隐藏实现细节的重要性

具体的类以非常具体的方式完成实际工作。例如,ArrayList使用一个连续的内存区域以紧凑的方式存储对象列表,这提供了快速的随机访问、迭代和就地更改,但在插入、删除和偶尔甚至添加时非常糟糕;同时,LinkedList使用双链接节点来存储对象列表,这提供了快速迭代、就地更改和插入/删除/添加,但在随机访问时非常糟糕。这两种列表针对不同的用例进行了优化,如何使用它们非常重要。当您试图从与您密切交互的列表中挤出性能时,当选择列表类型时,您应该仔细选择要实例化的列表。

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

抽象类位于接口和具体类之间。它应该帮助实现共享公共或无聊的代码。例如,AbstractCollection提供了基于大小为0的isEmpty的基本实现,包含作为迭代和比较,addAll作为重复添加等等。这让实现专注于区分它们的关键部分:如何实际存储和检索数据。

API与SPI

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

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

API和SPI之间的区别很细微,但很重要:对于API,重点是谁使用它,而对于SPI,重点是由谁实现它。

向API添加方法很容易,API的所有现有用户仍将编译。向SPI添加方法很难,因为每个服务提供商(具体实现)都必须实现新方法。如果使用接口定义SPI,则每当SPI合约发生变化时,提供商都必须发布新版本。如果改用抽象类,则可以根据现有的抽象方法定义新方法,或者将新方法定义为空抛出未实现的异常存根,这至少允许旧版本的服务实现仍然编译和运行。

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

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

使用哪一个?

这个东西应该由代码的其他部分或其他外部代码公开使用吗?向其添加一个接口,以从公共抽象契约中隐藏实现细节,这是该事物的一般行为。这件事是不是应该有多个实现,有很多共同的代码?既要做一个接口,又要做一个抽象的、不完整的实现。是否只有一个实现,而没有其他人会使用它?让它成为一个具体的课程。“ever”是一个很长的时间,你可以安全地使用它,并在它上面添加一个界面。

一个推论:另一种方法往往是错误的:当使用一个东西时,总是尝试使用您实际需要的最通用的类/接口。换句话说,不要将变量声明为ArrayListtheList=newArrayList(),除非您实际上对它是一个数组列表有很强的依赖性,并且没有其他类型的列表可以为您删除它。如果它是一个列表,而不是任何其他类型的集合这一事实实际上无关紧要,请改用ListtheList=newArrayList,甚至使用CollectiontheCollection=newArrayNist。


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

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

当我们已经有抽象类时,为什么要接口?Java只支持多级和分层继承,但借助于接口,我们可以实现多重继承。


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


界面:转弯(左转,右转)

抽象类:轮子。

类别:方向盘,衍生自方向盘,暴露接口转向

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


简而言之,差异如下:

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

抽象类的方法和成员可以具有任何可见性。接口的所有方法都必须是公共的//Java 9不再适用抽象类的具体子类必须定义所有抽象方法。抽象子类可以具有抽象方法。扩展另一个接口的接口不需要为从父接口继承的方法提供默认实现。子类只能扩展单个类。一个接口可以扩展多个接口。一个类可以实现多个接口。子类可以定义具有相同或更少限制性可见性的抽象方法,而实现接口的类必须将所有接口方法定义为公共的。抽象类可以有构造函数,但不能有接口。来自Java9的接口具有私有静态方法。

现在在界面中:

公共静态-支持公共摘要-支持公共默认值-支持私有静态-支持私有抽象-编译错误私有默认值-编译错误私有-支持


为了给出一个简单但明确的答案,设置上下文是有帮助的:当您不想提供完整的实现时,可以同时使用这两种方法。

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


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

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

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

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

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

抽象类示例:

 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");
            }
        }

接口示例:

  public interface IShape
        {
          // Defines the prototype(template) 
            void Draw();
        }


  // All the sub classes follow the same template but implementation can be different.

    public class Circle : IShape
    {
        public void Draw()
        {
            Console.WriteLine("This is a Circle");
        }
    }

    public class Rectangle : IShape
    {
        public void Draw()
        {
            Console.WriteLine("This is a Rectangle");
        }
    }

您可以发现接口和抽象类之间的明显区别。

界面

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

抽象类

抽象类包含抽象和非抽象方法。继承时不强制用户实现所有方法抽象类。包含所有类型的变量,包括基元和非基元使用abstract关键字声明。抽象类的方法和成员可以使用任何可见度子类只能扩展单个类(抽象或具体)。


如果您有一些可供多个类使用的通用方法,请使用抽象类。否则,如果你想让类遵循某种明确的蓝图,就去寻找接口。

以下示例演示了这一点。

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);
    }
}

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

默认情况下,Java接口中声明的变量是final。抽象类可以有非final变量。默认情况下,Java接口中声明的变量是静态的。抽象类可以具有非静态变量。默认情况下,Java接口的成员是公共的。Java抽象类可以具有类成员的通常风格,如private、protected等。。


抽象类和接口的一般思想是由使用这些通用“设置”(某种模板)的其他类(不能单独构建)来扩展/实现,这使得为以后扩展它的所有对象设置特定的通用行为变得简单。

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

接口与抽象类具有相同的财产,但只包含抽象方法,这些方法可以在其他类中实现(可以是多个要实现的接口),这就创建了一个更持久的方法/静态变量定义。与抽象类不同,您不能添加自定义的“常规”方法。


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

接口就像一个协议。它不指定对象的行为;它指定代码如何告诉该对象的动作。接口类似于英语:定义接口定义代码如何与实现该接口的任何对象通信。接口始终是一个协议或承诺。当一个类说“我实现接口Y”时,它就是说“我承诺拥有与任何具有接口Y的对象相同的公共方法”。另一方面,抽象类类似于部分构建的类。它很像是一个有空格要填写的文档。它可能使用英语,但这并不像某些文档已经写好这样重要。抽象类是另一个对象的基础。当一个类显示“I extend abstract class Y”时,它表示“I use some methods or properties already defined in this other class named Y”。因此,请考虑以下PHP:<?php文件类X实现了Y{}//这意味着“X”同意使用代码使用语言“Y”。类X扩展了Y{}//这意味着“X”将完成部分类“Y”。?>如果您正在分发一个类供其他人使用,那么您的类将实现一个特定的接口。接口是一个协议,为您的类提供一组特定的公共方法。如果您(或其他人)编写了一个已经编写了一些要在新类中使用的方法的类,则可以让您的类扩展一个抽象类。这些概念虽然很容易混淆,但却特别不同和不同。出于所有意图和目的,如果您是任何类的唯一用户,则不需要实现接口。


我们在接口和抽象类之间存在各种结构/语法差异。还有一些不同之处

[1] 基于场景的差异:

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

当我们确信不能提供更多抽象方法时,必须使用接口。然后只发布一个接口。

[2] 概念差异:

“我们是否需要在未来提供更多抽象方法”,如果是,则将其设为抽象类,如果否,则设为接口。

(在java 1.7之前最合适和有效)


通常抽象类用于某些东西的核心,但接口用于附加外围设备。

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

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

如果您使用vehicle作为参数,您可以使用它的派生类型之一(公共汽车或汽车同一类别只是车辆类别)。但当您使用IMoveable接口作为参数时,您有更多的选择。


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


我迟到10年了,但我想尝试任何方法。几天前写了一篇同样的帖子。我想把它张贴在这里。

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

面试问题:接口和抽象类有什么区别?你如何决定何时使用什么?我通常会得到以下一个或全部答案:答案1:不能创建抽象类和接口的对象。

ZK(这是我的首字母缩写):你不能创建任何一个对象。所以这并不是什么区别。这是接口和抽象类之间的相似之处。柜台问题:为什么不能创建抽象类或接口的对象?

答案2:抽象类可以有一个函数体作为部分/默认实现。

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

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

ZK:反问:你真的从接口继承吗?还是只实现一个接口,从抽象类继承?实现和继承之间有什么区别?这些反问题会让考生们措手不及,让大多数人挠头,或者直接进入下一个问题。这让我觉得人们需要帮助来构建面向对象编程的基本构件。原始问题和所有反问题的答案都可以在英语和UML中找到。为了更好地理解这两个结构,您必须至少了解以下内容。

共同名词:共同名词是指同一类或同一种类的事物的“共同”名称。例如水果、动物、城市、汽车等。

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

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

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

是A有A使用

让我们考虑下面的两句话。-本田雅阁是一辆车?-本田雅阁有车吗?

哪一个听起来正确?简单的英语和理解能力。本田雅阁(HondaAccord)和汽车(Cars)有着“是A”的关系。本田雅阁(Honda accord)没有车,它“是”一辆车。本田雅阁“有一个”音乐播放器。

当两个实体共享“Is A”关系时,它更适合继承。Has a relationship是创建成员变量的更好候选。这样,我们的代码如下所示:

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

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

因此,他们联系其他公司并签订合同。如果你在这里接收到电源和这两条电线上的输出信号,它在这些扬声器上会播放得很好。

这使得Music Player成为界面的完美候选。你不在乎谁为它提供支持,只要连接正常即可。

您可以用索尼或其他方式替换LG的MusicPlayer。这不会改变本田雅阁的任何事情。

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

因为你不能走进展厅说给我一辆车。你必须提供一个专有名词。什么车?可能是本田雅阁。这就是销售代理可以给你东西的时候。

为什么不能创建接口的对象?因为你不能走进展厅说给我一份音乐播放器的合同。这没用。接口位于消费者和提供者之间,只是为了促成协议。你将如何处理协议副本?它不会播放音乐。

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

接口未被继承。接口已实现。界面是与外部世界交互的候选界面。本田雅阁有一个加油接口。它有给轮胎充气的接口。和用来给足球充气的软管一样。因此,新代码如下所示:

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

英文的意思是“本田雅阁是一款支持轮胎充气和加油的汽车”。


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

抽象类在不同的编程语言中通常充当接口的超集,除了一点,即可以实现多个接口,但只能继承一个类。

接口定义了某件事情必须能够做的事情;类似于合同,但不提供其实现。

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

例如,格式化程序应该能够格式化()某些内容。描述这种情况的常见语义是创建一个接口IFormatter,该接口带有一个format()声明,其作用类似于一个契约。但是IFormatter并不描述什么是什么,而是描述它应该能够做什么。在本例中,我们创建一个抽象类。。。因此,我们创建了一个实现接口的抽象类Formatter。这是一个非常描述性的代码,因为我们现在知道我们有一个格式化程序,我们现在知道每个格式化程序必须能够做什么。

还有一个非常重要的主题是文档(至少对某些人来说…)。在您的文档中,您可能希望在子类中解释Formatter实际上是什么。有一个抽象类Formatter非常方便,您可以链接到子类中的文档。这是非常方便和通用的。另一方面,如果您没有抽象类Formatter,而只有接口IFormatter,则必须在每个子类中解释Formatter实际上是什么,因为接口是一个契约,你不会在接口的文档中描述Formatter实际上是什么-至少这不是常见的事情,你会打破大多数开发人员认为正确的语义。

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


之所以调用接口,是因为它向调用方(例如COM客户端)提供了由某个类实现的方法接口。通过将一个对象指针以多态的方式投射到对象类实现的接口的类型,它限制对象对其实现的接口中的函数和成员的访问,与coclass可能实现的其他COM接口分离。客户端不需要知道什么类实现了接口,或者该类中存在什么其他方法;对象以它所知道的接口实例的形式呈现(其中类的实例已被多态地转换为接口实例,该接口实例是类的子实例),它只是通过调用接口实例上的接口方法来使用接口。实际实现的所有细节和不同接口实现的无关功能/细节都与调用方期望的接口分离——调用方只使用它与对象的接口(接口实例及其作为对象一部分的虚拟表指针),并且调用底层对象实现,而调用者不必知道实现的位置或细节。通过接口(接口类型的指针)访问对象是一种封装形式,在语法上防止未经授权访问对象,并隐藏实现细节和其他与接口及其定义的个性无关的功能。

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


相似之处这两种方法都强制类扩展或实现它们来重写基方法。

差异

一个类可以实现多个接口。一个类只能从一个抽象类扩展。接口中声明的字段必须是静态的和最终的,因为从此类实现创建的所有对象共享相同的值。在抽象类中,字段可以被命名而不被分配。子类可以覆盖它们。

用例

抽象类用于密切相关或具有几乎相同功能和行为的子类中。接口用于不相关的类,因为它只是一个没有实现的契约,所以您希望强制执行某个事情或行为。