oop:接口和抽象类之间的区别是什么?

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


接口

接口是一种契约:编写接口的人说,"嘿,我接受这样看起来的东西",而使用接口的人说,"好吧,我编写的类是这样的"。

接口是一个空的shell。只有方法的签名,这意味着方法没有主体。接口不能做任何事情。这只是一种模式。

例如(伪代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 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,因为它不是一个类,只是一堆名称,因此不需要进行任何昂贵的查找。当它很重要的时候,比如在嵌入式设备中,它是伟大的。

抽象类

与接口不同,抽象类是类。它们使用起来更昂贵,因为当您从它们继承时需要进行查找。

抽象类看起来很像接口,但它们还有更多的功能:您可以为它们定义一个行为。这更像是一个人说,"这些类应该是这样的,它们有共同之处,所以请填空!"

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 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__方法)。

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


抽象类和接口之间的关键技术区别是:

抽象类可以有常量、成员、方法存根(没有主体的方法)和定义的方法,而接口只能有常量和方法存根。

抽象类的方法和成员可以用任何可见性定义,而接口的所有方法都必须定义为public(它们默认定义为public)。

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

类似地,扩展另一个接口的接口不负责实现来自父接口的方法。这是因为接口不能定义任何实现。

子类只能扩展一个类(抽象的或具体的),而接口可以扩展或类可以实现多个其他接口。

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


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

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


可以在这里找到一个解释:http://www.developer.com/lang/php/article.php/3604111/ php -5- oop - interface - abstract - class -and-the- adapter - pattern.htm

An abstract class is a class that is
only partially implemented by the
programmer. It may contain one or more
abstract methods. An abstract method
is simply a function definition that
serves to tell the programmer that the
method must be implemented in a child
class.

An interface is similar to an abstract
class; indeed interfaces occupy the
same namespace as classes and abstract
classes. For that reason, you cannot
define an interface with the same name
as a class. An interface is a fully
abstract class; none of its methods
are implemented and instead of a class
sub-classing from it, it is said to
implement that interface.

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


一些重要的差异:

以表格形式:

Difference

正如来自javapaper的Joe所说:

1.Main difference is methods of a Java interface are implicitly abstract and cannot have implementations. A Java abstract class can
have instance methods that implements a default behavior.

2.Variables declared in a Java interface is by default final. An abstract class may contain non-final variables.

3.Members of a Java interface are public by default. A Java abstract class can have the usual flavors of class members like private,
protected, etc..

4.Java interface should be implemented using keyword"implements"; A Java abstract class should be extended using keyword"extends".

5.An interface can extend another Java interface only, an abstract class can extend another Java class and implement multiple Java
interfaces.

6.A Java class can implement multiple interfaces but it can extend only one abstract class.

7.Interface is absolutely abstract and cannot be instantiated; A Java abstract class also cannot be instantiated, but can be invoked if a
main() exists.

8.In comparison with java abstract classes, java interfaces are slow as it requires extra indirection.


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

简单地说,我想说:

接口:通过多个不相关的对象实现契约

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

从Oracle文档中

考虑使用抽象类,如果:

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

考虑在以下情况下使用接口:

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

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

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

Java 8通过提供default方法特性,在一定程度上缩小了interfaceabstract类之间的差距。没有方法实现的接口现在不再有效。

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

为了更好地理解代码示例,请查看这个SE问题。

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


重点是:

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


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

建筑的蓝图界面

例如,Servlet(我)

高达200层的建筑——部分完成——摘要

部分实现,例如,通用和HTTP servlet

建筑completed-concrete

完整的实现,例如,拥有servlet

接口

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

摘要

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

摘自DurgaJobs网站


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

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


让我们再来看看这个问题:

首先要让你知道的是1/1和1*1的结果是一样的,但这并不意味着乘法和除法是一样的。很明显,他们的关系很好,但是要注意你们俩是不同的。

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

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

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


其实很简单。

您可以将接口看作一个类,它只允许有抽象方法,而不允许有其他任何东西。

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

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

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

最后一件事,

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

这意味着定义行为的继承被限制为每个类只允许一个…也就是说,如果你想要一个类来封装从类a,B&C的行为,你需要做以下工作:类a扩展B,类C扩展a ..这是一种多继承的迂回方式……

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

因此,实际上Java只在"声明的行为"ie接口中支持多重继承,并且只支持带有定义行为的单继承。除非你照我说的那样做……

希望这能说得通。


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

接口和类

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

1
2
3
interface Package {
  String address();
}

类是一组遵守契约的对象。我是"盒子"集团的一员,我服从邮递员的合同。同时遵守其他合同:

1
2
3
4
5
6
7
8
9
10
class Box implements Package, Property {
  @Override
  String address() {
    return"5th Street, New York, NY";
  }
  @Override
  Human owner() {
    // this method is part of another contract
  }
}

文摘vs最终

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

1
2
3
4
5
6
7
abstract class GpsBox implements Package {
  @Override
  public abstract String address();
  protected Coordinates whereAmI() {
    // connect to GPS and return my current position
  }
}

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

Final类是一组完整的对象,可以使用,但不能修改。他们知道如何工作和做什么。例如:I'm a Box that always go to the address during its construction:

1
2
3
4
5
6
7
8
9
10
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 9抽象类的具体子类必须定义所有抽象方法。抽象子类可以有抽象方法。扩展另一个接口的接口不需要为从父接口继承的方法提供默认实现。子类只能扩展一个类。一个接口可以扩展多个接口。一个类可以实现多个接口。子类可以定义具有相同或较少限制的可见性的抽象方法,而实现接口的类必须将所有接口方法定义为公共的。抽象类可以有构造函数,但不能有接口。Java 9中的接口具有私有的静态方法。

现在在接口:

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


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

接口的定义随着时间而变化。您是否认为接口仅仅具有方法声明并且仅仅是契约?那么静态最终变量和Java 8之后的默认定义呢?

接口被引入Java是因为多重继承的菱形问题,而这正是他们真正想做的。

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

请参阅为什么Java允许接口中只包含契约的静态最终变量?


接口:左转,右转。

抽象类:轮。

类:方向盘,派生自方向盘,公开接口转向

一个是对可以跨不同范围提供的行为进行分类,另一个是对事物的本体建模。


如果您有一些可以被多个类使用的通用方法,那么可以使用抽象类。否则,如果您想让类遵循某些明确的蓝图,可以使用接口。

下面的例子说明了这一点。

Java中的抽象类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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实现的接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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("****
* *
* *
****");
    }
    @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。抽象类可以有非最终变量。

默认情况下,Java接口中声明的变量是静态的。抽象类可以有非静态变量。

默认情况下,Java接口的成员是公共的。Java抽象类可以具有类成员的一般风格,如private、protected等。


这并不是最初问题的答案,但一旦你知道了它们之间的区别,你就会进入"什么时候使用"的两难境地:何时使用接口或抽象类?什么时候同时使用?

我对OOP的知识有限,但是把接口看作语法上的一个形容词一直对我很有用(如果这个方法是假的,请纠正我)。例如,接口名类似于可以赋予类的属性或功能,而类可以有许多属性或功能:ISerializable、ICountable、IList、ICacheable、IHappy、…


继承用于两个目的:

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

允许对一种类型的对象的引用被期望引用超类型对象的代码使用。

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

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

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


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


您可以在接口和抽象类之间找到明显的区别。

接口

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

抽象类

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

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

包含各种变量,包括基本变量和非基本变量

使用abstract关键字声明。

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

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


抽象类和接口之间的区别代表了实际实现。

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

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

两个外部对象之间的通信(我们的应用程序中的第三方集成)通过接口在这里接口作为契约工作。

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

抽象类的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 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");
            }
        }

接口的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  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");
        }
    }

重点:

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

优势:

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

在这里找到细节……http://pradeepatkari.wordpress.com/2014/11/20/interface-and-abstract-class-in-c-oops/


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

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


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

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

当您希望在契约中进行更改时,请使用抽象类。例如,将来您可能需要添加一个新方法。

在这种情况下,如果您决定使用一个接口,当该接口被更改为包含接口时,您的应用程序将在您转储新接口dll时崩溃。

要详细阅读,请访问抽象类和接口之间的差异


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

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

总结

接口定义了一些实现将为您完成的契约。

抽象类提供了实现可以重用的默认行为。

选择总结接口用于定义公共api抽象类用于内部使用和定义SPIs关于隐藏实现细节的重要性

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

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

抽象类位于接口和具体类之间。它应该帮助实现共享公共或无聊的代码。例如,AbstractCollection提供了基于大小为0的isEmpty的基本实现,contains作为迭代和比较,addAll作为重复的add,等等。这使得实现可以将重点放在区分它们的关键部分上:如何实际存储和检索数据。

api和spi

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

抽象类是在实现接口时使用的高内聚帮助器,假设有一定程度的实现细节。另外,抽象类用于定义SPIs(服务提供者接口)。

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

向API添加方法很容易,API的所有现有用户仍然会编译。向SPI添加方法很难,因为每个服务提供者(具体实现)都必须实现新方法。如果接口用于定义SPI,那么每当SPI契约发生更改时,提供者就必须发布一个新版本。如果使用抽象类,则可以根据现有的抽象方法定义新方法,或者将其定义为空的throw not implemented exception存根,这至少允许仍然编译和运行服务实现的旧版本。

一个关于Java 8和默认方法的注释

尽管Java 8介绍了接口的默认方法,使线之间的接口和抽象类甚至更模糊,这不是以便实现可以重用代码,但是,让它更容易改变接口,提供一个API, SPI(或错误的用于定义SPI而非抽象类)。

使用哪一个?它应该被代码的其他部分公开使用,还是被其他外部代码公开使用?向其添加一个接口,以对公共抽象契约隐藏实现细节,这是事物的一般行为。这个东西应该有多个实现,并且有很多代码是相同的吗?同时创建一个接口和一个抽象的、不完整的实现。是否只有一个实现,而没有其他人使用它?让它成为一个具体的类。"ever"是很长的一段时间,你可以玩得很安全,还可以在上面添加一个界面。

一个推论:另一种方法常常是错误的:当使用一个东西时,总是尝试使用您实际需要的最通用的类/接口。换句话说,不要将变量声明为ArrayList theList = new ArrayList(),除非您实际上非常依赖于它是一个数组列表,并且没有其他类型的列表可以为您删除它。而是使用List theList = new ArrayList,或者甚至是Collection theCollection = new ArrayList,如果它是一个列表,而不是任何其他类型的集合实际上并不重要。


简而言之,an interface是:

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

同时,一个abstract类为:

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

或者,如果我们想将其归结为一句话:interface是实现类的内容,而abstract类是子类的内容。


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

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

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


通常抽象类用于核心,接口用于附加外设。

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

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

enter image description here

如果使用vehicle作为参数,则可以使用它的派生类型之一(bus或car-same category-just vehicle category)。但是当您使用IMoveable接口作为参数时,您有更多的选择。


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

An Interface is like a protocol. It doesn't designate the behavior of the object; it designates how your code tells that object to act. An interface would be like the English Language: defining an interface defines how your code communicates with any object implementing that interface.

An interface is always an agreement or a promise. When a class says"I implement interface Y", it is saying"I promise to have the same public methods that any object with interface Y has".

On the other hand, an Abstract Class is like a partially built class. It is much like a document with blanks to fill in. It might be using English, but that isn't as important as the fact that some of the document is already written.

An abstract class is the foundation for another object. When a class says"I extend abstract class Y", it is saying"I use some methods or properties already defined in this other class named Y".

So, consider the following PHP:

1
2
3
4
5
<?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".
?>

You would have your class implement a particular interface if you were distributing a class to be used by other people. The interface is an agreement to have a specific set of public methods for your class.

You would have your class extend an abstract class if you (or someone else) wrote a class that already had some methods written that you want to use in your new class.

These concepts, while easy to confuse, are specifically different and distinct. For all intents and purposes, if you're the only user of any of your classes, you don't need to implement interfaces.


在一个接口中,所有的方法都必须是定义,而不是单个方法。

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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
}

}

我们只需要

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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
}

}

现在是面积计算器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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();

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

什么时候使用抽象?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

}

抽象应该用在不需要类实例的时候,有类似的逻辑,需要契约的时候。


enter image description here

下面是对接口和抽象类的基本理解。


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

抽象类有规则方法集和抽象方法。扩展类可以在被抽象类扩展后包含未设置的方法。当设置抽象方法时——它们是由稍后扩展它的类定义的。

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


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

基于[1]场景的差异:

抽象类用于限制用户创建父类对象的场景,我们相信将来会添加更多的抽象方法。

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

[2]概念的区别:

"我们是否需要在未来提供更多的抽象方法",如果是,让它抽象类,如果不是,让它接口。

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