什么时候应该在Java中使用接口?
一个理想的例子是什么时候确切地使用Java中的特定接口,以及适用的任何特定规则。
Julio asked 2020-02-17T01:40:08Z
12个解决方案
66 votes
集合框架是一个不错的选择。
java.util.List //interface
java.util.ArrayList //Concrete class
java.util.LinkedList //Concrete class
因此,您可以编写如下代码:
List l = new ArrayList();
l.add(..)
//do something else.
如果将来您想要更改说LinkedList的实现或拥有自己的27508920789966530530接口,那么您要做的就是将第一行更改为:
List l = new MyAwesomeList();
or
List l = new LinkedList();
其余代码将继续进行。
coolest_head answered 2020-02-17T01:41:03Z
35 votes
使用接口定义“第三方”供应商必须完全遵守和实现的应用程序编程合同(蓝图,接口)。 这样,最终用户就可以根据API合同进行编码,并且可以轻松地在“幕后”切换具体的实现,而无需更改代码。
JDBC API是一个很好的例子。 它几乎只存在接口。 具体实现以“ JDBC驱动程序”的形式提供。 这使您能够独立于数据库(DB)供应商编写所有JDBC代码。 每当您要切换数据库供应商时,只需更改JDBC驱动程序而无需更改任何Java代码行(任何硬编码的特定于DB的SQL代码除外)。
另一个示例是Java EE API,它还包含很多接口和抽象类。 具体实现以“ Java EE应用程序服务器”,“ Servlet容器”等(例如Sun Glassfish,Apache Tomcat等)的形式提供。这使您可以将Web应用程序(WAR)部署到所需的任何Java Web服务器上。
BalusC answered 2020-02-17T01:40:30Z
14 votes
在您希望程序波动的地方,需要更改的地方,需要弯曲的地方都需要接口。
从这个意义上说,实现是脆弱的:它很容易中断。 这就是为什么子类化不一定总是最好的解决方案的原因,就像长距离执行的方法本身全部实现某些复杂行为一样,通常是个坏主意。
接口比实现更灵活,并且可以在程序设计上处理更多的压力。
通过在程序中引入接口,您实际上引入了变化点,您可以在该点上插入该接口的不同实现。 接口的主要目的是抽象,将“什么”与“如何”分离。
安全记住这一重要规则是Liskov替代原则[UncleBob,维基百科]。 虽然使用Java之类的语言进行的编译器将确保语法上的所有内容都正确无误(参数,类型等的正确数量),但是LSP处理语义。 简而言之,LSP表示,接口的每个实现都必须(也)正确地发挥自身作用,以便如上所述能够真正被替换。
eljenso answered 2020-02-17T01:41:42Z
6 votes
从oracle文档页面
如果满足以下条件,请考虑使用接口:
您期望不相关的类将实现您的接口。 例如,许多不相关的对象可以实现Serializable接口。
您想指定特定数据类型的行为,但不关心谁实现了它的行为。
您想利用类型的多重继承。
看看相关的SE问题以及代码示例,这些示例已经有了很好的答案。
除了拥有正确的方法之外,接口还有更多其他功能
接口和抽象类之间有什么区别?
我应该如何解释接口和抽象类之间的区别?
Ravindra babu answered 2020-02-17T01:42:37Z
4 votes
在链接文本中查看JDK收集教程。 考虑收藏。 你想到什么? 它可以订购,也可以不订购,也可以重复。
因此,Collection是一个以List(有序)和Set(无序)为子接口的接口。 现在,列表有很多问题,是否应该同步,是否应该是链表等等。每个“行为”都有自己的接口/抽象类。
当您要在集合中指定“某些”行为时,需要抽象类。 例如,所有集合(集合/列表等)都可以具有“ toString”表示形式,该表示形式仅对元素进行迭代(有序/无序)并将其字符串化。 该行为可以出现在“ AbstractCollection”等中。
如果遵循JDK集合的层次结构,那么它是学习接口和抽象类的绝佳场所:)
Kannan Ekanath answered 2020-02-17T01:43:11Z
4 votes
尝试了解策略设计模式
Boris Pavlović answered 2020-02-17T01:43:31Z
3 votes
当需要相同行为的多个实现时,将使用接口。 这是对象可以实现的接口示例,以表明它们都可以序列化为XML。
public interface Xmlizable
{
public String toXML();
}
那么您可以将“ Xmlizable”接口传递给只关心该接口的方法。
answered 2020-02-17T01:43:55Z
3 votes
基本上,当您需要“省略”一些实现细节时,可以在接口和抽象类之间进行选择。 接口通常是更好的选择,因为客户端类可以实现任何数量的接口,但是它们只能具有一个超类(如他们所说,“继承是一种稀缺资源”)。
为什么要抽象类或接口? 因为有时候,当您编写算法时,您并不关心它的特定子步骤是如何完成的,而只是根据某种合同来完成它。 一个示例就是Collections API,其中List是一个接口-通常,当您使用AbstractList时,您实际上并不关心它是否将内容保存在数组,节点的链接列表或其他某种形式的文件中。 办法。 只要它按照您放入的顺序存储放入其中的东西,您就很高兴。
然后我们有AbstractList:实现List的抽象类,该类提供了List几乎所需要的几乎所有内容的实现-要创建自己的List实现,您要做的就是扩展AbstractList并填写一些方法。 这是一个很好的例子,说明抽象类是一个不错的选择-当您想要提供某种东西的几乎完整的实现时,它只缺少一些空白,需要由客户端代码来填补。
提示:如果您创建一个仅包含抽象方法的抽象类,则可能应该为其创建一个接口。
gustafc answered 2020-02-17T01:44:31Z
3 votes
这个答案与coolest_head的答案基本相同,只是在传达有用性方面更为明确。
正如coolest_head解释的那样,当您将来可能希望在程序的可能子组件之间切换时,接口很有用。 它们还使您可以更轻松地将程序结构各部分的关注点分开,因为使用接口可以确保某些不相关的类等对于程序的其他部分而言是不可见的。
例如,假设您要读取任意数据并进行打印,如下所示:
SomeReader someReader = new SomeReader();
String data = someReader.readLine();
System.out.println(data);
这里没什么好看的,对吧? 但是,尽管此示例很简单,但已与new类绑定,这意味着您对该类所做的所有更改都必须传播到您使用该类的类中,尤其是在重构某些内部组件时! 相反,您想这样做
IMyReader reader = new SomeReader();
System.out.println(reader.readLine());
您差不多就在那里了-现在打印代码不再关心特定的实现,而只关心界面暴露的部分。 这通常就足够了,因为现在您只需切换一个new语句,就可以得到新的实现以及仍然可以按预期运行的任何实现(只要在实现类中遵守接口的约定!)。 当您最终多次使用一个特定的对象时,这特别方便-在这里我只使用一次,但实际上,如果您使用的是例如列表,则通常要执行同一列表的多少个操作?
因此,要真正使这个示例不成比例,这就是您的代码可能最终看起来像的样子
public class RowPrinter {
private final IMyReader reader;
public RowPrinter(IMyReader reader) {
this.reader = reader;
}
public void print() {
IMyReader reader = getReader();
System.out.println(reader.readLine());
}
protected IMyReader getReader() {
return reader;
}
}
注意构造器的那一部分吗? 那是控制的倒置,让我告诉您,那是那里的一个很棒的软件工程。 从经验上我可以说,无论是从数据库产品切换到另一种产品,还是使代码线程的某些部分安全,它都可以为您带来很多麻烦。 或者,也许您只想向某个类添加一个日志记录层,就可以使用包装装饰器轻松实现该功能,该包装装饰器恰好实现与包装的类相同的接口。 而这仅仅是个开始。
界面带来了很多好处,尽管简单的示例确实可以使您正常工作,但通常从简单的示例中并没有那么明显。 尽管Java中的接口是一种语言构造,但它们实际上更像是一种编程范例,而不仅仅是一种语言的功能,在某些语言中,如果您找出正确的接口方式,那么对接口进行仿真确实是非常有益的。
Esko answered 2020-02-17T01:45:25Z
2 votes
OOP的基本原理是信息隐藏:隐藏实现细节,仅向调用者显示基本服务的描述。
Java必须为此目标构造:接口和抽象类。 您可以定义一个接口并编写代码,使其仅依赖于该接口,方法是调用其中定义的“可用方法”。
信息隐藏可用于读取外部类(在某种意义上来说,外部是外部的,它在您正在编写的模块之外)-这样,您可以定义所需的方法,而无需推断其具体实现类型-或何时 定义在您的类之外可用的数据类型-例如,典型的例子是 如前面已经提到的,Collection API或J2EE。
接口和抽象类都提供了这些详细信息-但是有两个主要区别:接口支持多重继承,而抽象类可以容纳基本实现。 为了最大程度地提高它们的效率,在定义接口时,还应该定义一个有意义的默认实现的抽象类。 如果接口的用户不需要扩展任何其他类,则可以扩展此抽象类,否则它需要从接口实现所有方法。 另一方面,请确保不要直接读取此抽象类,该接口应足以作为抽象。
Zoltán Ujhelyi answered 2020-02-17T01:46:00Z
2 votes
远程通讯接口:
接口也可以用于定义一个约定的“协议”,以便可能通过远程调用在系统的不同部分之间进行通信。 因此,接口仅定义可以调用的内容,参数以及调用后将返回的内容。 客户端使用该接口,而服务器则实现具体的实际代码。
边注:
在Java中,您只能从一个类中固有(扩展),但是您可以实现多个接口,因此有时当您需要这种多重继承并且决定不对继承使用合成时,必须使用接口。
bakkal answered 2020-02-17T01:46:34Z
1 votes
每当您计划在某个开发点将实现类替换为另一个类时,请使用接口。
我还建议至少在更严重的项目中对继承关系中的所有类都使用接口后端:不幸的是,我不再具有链接,但是使用Java语言的开发人员曾经说过,包括类继承是最大的错误。 设计语言。
这些参数非常好:使用适当的设计,总是可以用接口继承替换类继承,并且您会获得很多有关代码维护的知识。 与使用类继承相比,保留自然类型关系(例如,根据几何图形(“正方形是矩形”))也更容易。
Searles answered 2020-02-17T01:47:04Z