【问题标题】:When should I use an interface in java? [closed]我什么时候应该在java中使用接口? [关闭]
【发布时间】:2011-02-04 21:29:52
【问题描述】:

一个很好的例子,说明何时在 Java 中专门使用接口是理想的,任何适用的特定规则都是理想的。

【问题讨论】:

  • 查看 Dan 之前发布的所有问题,似乎他只是逐字发布作业/考试问题。
  • 令人惊讶的是,这些不是考试问题或其他......今天才发现这个网站,所以我想我会尝试在我脑海中得到一些答案。感谢大家的回复,这些回复非常有助于为我指明正确的方向。
  • 已经有非常非常多的问题了。您已经找到了搜索框,以防万一有人以前问过类似的问题?

标签: java interface


【解决方案1】:

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

public interface Xmlizable
{
    public String toXML();
}

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

【讨论】:

  • 然后在该示例中,您可以在将其传递给公共代码之前调用toXML
【解决方案2】:

集合框架是一个值得关注的地方。

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
  • 这是理解接口的简单且最佳的方式。
  • 非常感谢!这真的很清楚也很有帮助:)
【解决方案3】:

link text 上查看 JDK 集合教程。想想收藏。你会想到什么?可以订购,也可以不订购,可能有重复,也可能没有。

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

当您想在集合中指定“某些”行为时,需要抽象类。例如,所有集合(集合/列表等)都可以有一个“toString”表示,它只是迭代元素(有序/不有序)并将它们字符串化。这种行为可以出现在“AbstractCollection”等中。

如果您遵循 JDK 集合的层次结构,这是学习接口和抽象类的好地方:)

【讨论】:

    【解决方案4】:

    【讨论】:

      【解决方案5】:

      使用接口来定义“第三方”供应商必须完全遵守和实施的应用程序编程合同(蓝图、接口)。这样,最终用户只需根据 API 合约编写代码,即可轻松切换“幕后”的具体实现,而无需更改代码。

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

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

      【讨论】:

      • JDBC API 是不是一个过时设计的例子。那里有很多没有人使用的接口。 DB 供应商通常提供javax.sql 的一些实现,但实现连接池的库几乎从不使用它们,通常只需要Driver 实现。现在真的有必要拥有StatementPreparedStatement 吗?应该有更好的方法来设计ResultSet 接口,或许可以通过使用泛型来减少getXX()updateXXX() 方法的数量...
      【解决方案6】:

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

      为什么要抽象类或接口?因为有时,当您编写算法时,您并不关心如何完成它的特定子步骤,只需 它是根据某种合同完成。一个例子是 Collections API,其中 List 是一个接口 - 通常,当您使用 List 时,您并不真正关心它是将内容保存在数组中还是在链表中节点,或以其他方式。只要它按照您放入的顺序存储您放入其中的东西,您就会很开心。

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

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

      【讨论】:

        【解决方案7】:

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

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

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

        【讨论】:

          【解决方案8】:

          OOP 的一个基本原理是信息隐藏:隐藏实现细节,只向调用者显示基本服务的描述。

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

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

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

          【讨论】:

            【解决方案9】:

            远程通信接口:

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

            旁注:

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

            【讨论】:

              【解决方案10】:

              这个答案与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 中的接口是一种语言结构,但它们实际上更像是一种编程范式,而不仅仅是一种语言的特性,在某些语言中,如果您找到正确的方法,模拟接口确实是有益的。

              【讨论】:

                【解决方案11】:

                在您预计程序会发生波动的地方、您预计会发生变化的地方、您的设计需要弯曲的地方都需要接口。

                从这个意义上说,实现是脆弱的:它很容易崩溃。这就是为什么子类化并不总是最好的解决方案,就像完全靠自己实现一些复杂行为的冗长方法通常是一个坏主意一样。

                接口更灵活,可以处理比实现更多的程序设计压力。

                通过在您的程序中引入接口,您实际上引入了变化点,您可以在这些点为该接口插入不同的实现。接口的主要目的是抽象,将“what”与“how”解耦。

                为了安全地这样做,要牢记的一个重要规则是 Liskov 替换原则 [UncleBob, Wikipedia]。虽然像 Java 这样的语言的编译器会确保在语法上一切都井井有条(正确数量的参数、类型等),但 LSP 处理的是语义。简而言之,LSP 说,接口的每个实现都必须(也)正确地表现自己才能真正可替代,如上所述。

                【讨论】:

                • 感谢您的回答!对于其他阅读本文的人:UncleBob 链接已失效,因为他有一个新网站/域。文章仍然托管在他的 Google 驱动器上。通过在他的article page 中搜索“Liskov”来找到它
                【解决方案12】:

                来自 oracle 文档page

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

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

                查看相关的 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?

                【讨论】:

                  猜你喜欢
                  • 2022-01-02
                  • 2012-12-23
                  • 2021-07-13
                  • 1970-01-01
                  • 2010-12-13
                  • 2017-09-11
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多