接口和抽象类之间到底有什么区别?
当前回答
代表实际实现的抽象类和接口之间的差异。
接口:它是一个关键字,用于定义对象的模板或蓝图,它强制所有子类遵循相同的原型,作为实现,所有子类都可以根据其要求自由实现功能。
我们应该使用接口的一些其他用例。
两个外部对象(应用程序中的第三方集成)之间的通信通过此处的接口完成。
抽象类:抽象,它是一个关键字,当我们在任何类之前使用这个关键字时,它就成为抽象类。它主要用于我们需要定义模板以及所有子类后面的对象的一些默认功能时,这样它就删除了多余的代码和一个可以使用抽象类的用例,例如,我们不希望其他类可以直接实例化该类的对象,只有派生类可以使用该功能。
抽象类示例:
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");
}
}
其他回答
其实很简单。
您可以将接口视为一个类,它只允许有抽象方法,而不允许有其他方法。
因此,接口只能“声明”而不能定义您希望类具有的行为。
抽象类允许您声明(使用抽象方法)和定义(使用完整方法实现)您希望类具有的行为。
常规类只允许您定义而不是声明您希望类具有的行为/动作。
最后一件事,
在Java中,可以实现多个接口,但只能扩展一个(抽象类或类)。。。
这意味着定义行为的继承被限制为每个类只允许一个。。。例如,如果你想要一个从类a、B和C中封装行为的类,你需要执行以下操作:类a扩展B,类C扩展a。。这是一个有点迂回的方式来拥有多重继承。。。
另一方面,您可以简单地执行接口:接口C实现A、B
因此实际上,Java只在“声明的行为”(即接口)中支持多重继承,并且只支持具有定义行为的单一继承。。除非你像我描述的那样。。。
希望这是合理的。
许多初级开发人员错误地将接口、抽象类和具体类视为同一事物的细微变化,并纯粹基于技术原因选择其中之一:我需要多重继承吗?我需要一些地方来放置常用方法吗?除了一堂具体的课,我还需要为别的事情而烦恼吗?这是错误的,隐藏在这些问题中的是主要问题:“我”。当你自己编写代码时,你很少想到其他现在或将来的开发人员正在处理或使用你的代码。
接口和抽象类,虽然从技术角度看很相似,但有着完全不同的含义和目的。
总结
接口定义了某个实现将为您实现的契约。抽象类提供了您的实现可以重用的默认行为。
备选摘要
接口用于定义公共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。
实际上并不是最初问题的答案,但一旦你找到了它们之间的区别的答案,你就会进入何时使用每一个困境:何时使用接口或抽象类?何时同时使用两者?
我对OOP的了解有限,但将接口视为语法中形容词的等价物对我来说一直有效(如果这个方法是假的,请纠正我!)。例如,接口名称类似于可以赋予类的属性或功能,并且类可以具有许多属性或功能:ISerializable、ICountable、IList、ICacheable、IHappy。。。
为了给出一个简单但明确的答案,设置上下文是有帮助的:当您不想提供完整的实现时,可以同时使用这两种方法。
因此,主要的区别是接口根本没有实现(只有没有主体的方法),而抽象类也可以有具有主体的成员和方法,即可以部分实现。
在实用性方面(JAVA),抽象类和接口之间的主要区别是抽象类可以保存状态。除了保持状态,我们还可以使用Interface实现其余操作。
推荐文章
- Java抽象接口
- 什么是依赖倒置原则?为什么它很重要?
- 为什么在Python方法中需要显式地有“self”参数?
- 如何在方法中访问“静态”类变量?
- 为什么c#不提供c++风格的'friend'关键字?
- String, StringBuffer和StringBuilder
- 如何在python抽象类中创建抽象属性?
- 存储库和服务层的区别?
- DDD -实体不能直接访问存储库的规则
- 为什么STL如此严重地基于模板而不是继承?
- 如何在Objective-C中声明类级属性?
- 面向方面编程与面向对象编程
- c++中类似于java的instanceof
- 在python中遍历对象属性
- 将类代码分离为头文件和cpp文件