我什么时候应该在java中使用接口?

时间:2010-04-06 16:12:59

标签: java interface

在Java中专门使用接口的一个很好的例子是理想的,并且适用于任何特定的裁决。

12 个答案:

答案 0 :(得分:61)

要看的好地方是收藏框架。

java.util.List //interface

java.util.ArrayList //Concrete class
java.util.LinkedList //Concrete class

所以你可以写这样的代码:

List l = new ArrayList();

l.add(..)
//do something else.

如果以后您希望使用LinkedList或您拥有AwesomeList which implements List界面来更改实施,您只需将第一行更改为:

List l = new MyAwesomeList();
or
List l = new LinkedList();

其余代码将贯彻执行。

答案 1 :(得分:34)

使用接口来定义“第三方”供应商必须完全遵守和实施的应用程序编程合同(蓝图,接口)。通过这种方式,最终用户可以根据API合同进行编码,并在不改变代码的情况下轻松切换“引擎盖下”的具体实现。

JDBC API就是一个很好的例子。它几乎只存在接口。具体实现提供为“JDBC驱动程序”。这使您可以独立于数据库(DB)供应商编写所有JDBC代码。只要您想切换数据库供应商,就可以在不更改任何Java代码行的情况下更改JDBC驱动程序(除了任何硬编码的特定于SQL的SQL代码)。

另一个例子是Java EE API,它还包含很多接口和抽象类。具体实现提供为“Java EE应用程序服务器”,“Servletcontainers”等,例如Sun Glassfish,Apache Tomcat等。这使您可以将Web应用程序(WAR)部署到您喜欢的任何Java Web服务器。

答案 2 :(得分:12)

如果您希望程序存在波动性,预期变化的点数,设计需要弯曲的点,则需要接口。

在这个意义上,实施是脆弱的:它很容易打破。这就是为什么子类化并不总是最好的解决方案,就像实现一些复杂行为的冗长方法一般都是一个坏主意。

接口更灵活,可以对程序设计施加更多压力,而不是实现。

通过在程序中引入接口,您真正引入了变量点,您可以在其中插入该接口的不同实现。接口的主要目的是抽象,将“what”与“how”分离。

安全这样做的一个重要规则是 Liskov替代原则 [UncleBobWikipedia]。虽然像Java这样的语言的编译器将确保语法上的所有内容都是有序的(正确数量的参数,类型......),但LSP处理语义。简而言之,LSP表示接口的每个实现必须(也)正确地表现为真正可替代,如上所述。

答案 3 :(得分:6)

来自oracle文档page

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

  1. 您希望不相关的类会实现您的界面。例如,许多不相关的对象可以实现Serializable接口。
  2. 您希望指定特定数据类型的行为,但不关心谁实现其行为。
  3. 您希望利用类型的多重继承。
  4. 使用代码示例查看相关的SE问题,这些代码示例已经有了很好的答案。

    Is there more to an interface than having the correct methods

    What is the difference between an interface and abstract class?

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

答案 4 :(得分:4)

link text查看JDK集合教程。想想收藏品。你有什么想法?它可能是订购的,也可能没有订购,也可能有重复。

So Collection是一个以List(有序)和Set(无序)作为子接口的接口。现在列表中有很多问题,如果是同步还是不同,它是否应该是链表等。每个“行为”都有自己的接口/抽象类。

当您想要在集合中指定“某些”行为时,需要抽象类。例如,所有集合(集合/列表等)都可以具有“toString”表示,该表示仅迭代元素(有序/无)并对它们进行字符串化。该行为可以出现在“AbstractCollection”等中。

如果您遵循JDK集合的层次结构,那么它是学习接口和抽象类的绝佳场所:)

答案 5 :(得分:4)

答案 6 :(得分:3)

当您需要多个相同行为的实现时,将使用接口。下面是一个对象可以实现的接口示例,以显示它们都可以序列化为XML。

public interface Xmlizable
{
    public String toXML();
}

然后你可以将“Xmlizable”接口传递给只关心那个接口的方法。

答案 7 :(得分:3)

基本上,当您需要“省略”某些实现细节时,您可以在接口和抽象类之间进行选择。接口通常是更好的选择,因为客户端类可以实现任意数量的接口,但是它们只能有一个超类(“继承是稀缺资源”,正如他们所说的那样)。

为什么要一个抽象类或接口?因为有时候,当你编写算法时,你并不关心如何完成它的特定子步骤,只是根据某种契约完成。一个例子是Collections API, List 是一个接口 - 通常,当你使用List时,你真的不在乎它是在数组中保存东西,还是在链接的节点列表,或以其他某种方式。只要它按照你把它放在那里的顺序存放你放入的东西,你就会很高兴。

然后我们有AbstractList:一个实现List的抽象类,它提供了几乎所有完全成熟的List需求的实现 - 来创建自己的List实现,您所要做的就是扩展AbstractList并填写几种方法。这是一个很好的例子,当抽象类是一个很好的选择 - 当你想提供一个几乎完整的东西实现时,只缺少一些需要由客户端代码填补的空白。

提示:如果你创建一个只包含抽象方法的抽象类,你应该创建一个接口。

答案 8 :(得分:3)

这个答案与coolest_head基本相同,只是更明确地传达了它的用处。

正如coolest_head所解释的那样,当您可能希望将来切换程序的可能子组件时,接口非常有用。它们还允许您更轻松地分离程序结构各个部分的关注点,因为使用接口可以确保某些非相关类等对程序的其他部分不可见。

例如,假设您想要读取任意数据并将其打印出来,如下所示:

SomeReader someReader = new SomeReader();
String data = someReader.readLine();
System.out.println(data);

这里没什么好看的,对吗?但是,虽然这个例子很简单,但它已经绑定到SomeReader类,这意味着您对该类所做的所有更改必须传播到您正在使用该类的类中 - 特别是如果你重构一些内部零件!相反,你想要这样做

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

注意部分与构造函数?那是inversion of control,让我告诉你,那是一个很酷的软件工程。我可以从经验中说出它可以帮助你解决很多麻烦,无论是从数据库产品转换到另一个产品还是使代码的某些部分线程安全。或者您可能只想在某个类中添加一层日志记录,使用包装decorator可以轻松实现,这恰好可以实现与包装类相同的接口。这只是一个开始。

接口带来了许多好处,这些好处通常从简单的示例中不那么明显,尽管简单的示例确实可以帮助您顺利进行。虽然Java中的接口是一种语言结构,但它们实际上更像是一种编程范式,而不仅仅是单一语言的一种特性,在某些语言中,如果你找到正确的方法,仿真接口真的是有益的。

答案 9 :(得分:2)

OOP的基本原则是信息隐藏:隐藏实现细节,并仅向调用者显示基本服务的描述。

Java必须为此目标构建:接口和抽象类。您可以定义一个接口,并编写代码,它只依赖于接口,通过调用其中定义的“可用方法”。

信息隐藏既可用于读取外部类(从某种意义上说它位于您正在编写的模块之外) - 这样您就可以定义所需的方法,并且无需推断其具体实现类型 - ,或者在定义在类之外可用的数据类型时 - 例如,一个典型的例子收集API或J2EE,与其他已经提到的一样。

接口和抽象类都提供了这些细节 - 但是有两个主要区别:接口支持多重继承,而抽象类可以包含基本实现。为了最大限度地提高效率,在定义接口时,还应该定义一个具有有意义的默认实现的抽象类。如果接口的用户不需要扩展任何其他类,则可以扩展此抽象类,否则需要从接口实现所有方法。另一方面,请确保不要直接读取此抽象类,接口应该足以作为抽象。

答案 10 :(得分:2)

远程通信中的接口:

接口也可用于定义商定的“协议”,用于在系统的不同部分之间进行通信,可能通过远程调用。因此,接口只定义可以调用的内容,使用什么参数以及调用后返回的内容。客户端使用接口,服务器实现具体实际代码。

旁注:

在Java中,您只能从一个类中固有(扩展),但是您可以实现多个接口,因此有时您需要在需要这种多重继承时使用接口,并且当您决定不使用合成时继承。

答案 11 :(得分:1)

每当您计划在某个开发阶段用另一个类替换实现类时,请使用接口。

我还建议至少在更严肃的项目中为继承关系中的所有类使用接口后端:不幸的是我没有链接了,但Java语言的开发人员曾经说过,包括Class-Inheritance是设计语言的最大错误。

参数非常好:使用适当的设计,总是可以通过接口继承替换类继承,并且您在代码维护方面获得了很多。保留自然类型关系也更容易(例如,从几何(“正方形是矩形”-stuff)而不是类继承。