【问题标题】:Why doesn't interfaces implement methods and override them?为什么接口不实现方法并覆盖它们?
【发布时间】:2013-11-10 13:20:12
【问题描述】:

我已经阅读了the post 发布 SO 问题所需的研究工作。我再次羞于将这个问题发布到一堆百万问题中。但我仍然不明白java中的接口。它们具有未实现的方法,然后为实现它们的每个类定义。我搜索了一下。接口用于支持 java 中的多重继承,也用于避免继承的(致命的)钻石死亡。我还遇到了Composition vs Inheritance,继承不是为了代码重用,而是为了多态。因此,当我有一个通用代码作为一个类来扩展它时,由于多重继承提供了使用接口的选项(如果我错了,请纠正我),它将不受支持。我还发现在大多数情况下定义通用实现是不可能的。那么有一个接口方法的通用定义(不是完美的通用实现)然后在必要的地方覆盖它有什么问题,为什么java不支持它。例如。当我有 100 个实现接口的类时,其中 70 个有一个共同的实现,而其他的有不同的实现。为什么我必须在超过 70 个类的接口中定义通用方法,为什么我不能在接口中定义它们然后在其他 30 个类中覆盖它们,这使我免于在 70 个类中使用相同的代码。我对接口的理解有误吗?

【问题讨论】:

标签: java inheritance interface


【解决方案1】:

首先,Java 中的接口(从 Java 7 开始)没有代码。这只是一个定义,一个类必须履行的契约。

那么有一个共同的定义有什么问题(不是完美的 通用实现)接口方法,然后覆盖它 任何必要的地方,为什么java不支持它

是的,你可以在 Java 中做到这一点,只是不能只使用接口。假设我想从这个Example 接口中获得method1 的默认实现,但让method2 未实现:

interface Example {
   public void method1();
   public String method2(final int parameter);
}

abstract class AbstractExampleImpl implements Example {
    @Override
    public void method1() {
        // Implement
    }
}

现在想要使用这个method1 默认实现的类可以扩展AbstractExampleImpl。这比在接口中实现代码更灵活,因为如果您这样做,那么所有类都绑定到您可能不想要的实现。这就是接口的优点:能够引用某个行为(contract),而不必知道类实际是如何实现的,例如:

List<String> aList = MyListFactory.getNewList();

MyListFactory.getNewList() 可以返回任何实现List 的对象,我们处理aList 的代码根本不关心,因为它是基于接口的。


如果使用接口的类已经是子类怎么办。然后我们 不能使用抽象类,因为不支持多重继承

我猜你的意思是这种情况:

class AnotherClass extends AnotherBaseClass

你也想扩展AbstractExampleImpl。是的,在这种情况下,不可能使 AnotherClass 扩展 AbstractExampleImpl,但您可以编写一个包装的内部类来执行此操作,例如:

class AnotherClass extends AnotherBaseClass implements Example {
    private class InnerExampleImpl extends AbstractExampleImpl {
        // Here you have AbstractExampleImpl's implementation of method1
    }
}

然后,您可以通过调用 InnerExampleImpl 的方法在内部使所有 Example 方法实际实现。


AnotherClass中必须要有接口吗?

我猜你的意思是AnotherClass implements Example。好吧,这就是你想要的:让AnotherClass 用一些默认实现实现Example 并扩展另一个类,否则我理解你错了。由于您不能扩展多个类,因此您必须实现接口以便您可以这样做

final Example anotherClass = new AnotherClass();

否则这是不可能的。

对于每个实现接口的类,我是否必须设计 内部类?

不,它不必是内部类,这只是一个示例。如果您希望多个其他类具有此默认 Example 实现,您可以编写一个单独的类并将其包装在您想要的所有类中。

class DefaultExampleImpl implements Example {
   // Implements the methods
}

class YourClass extends YetAnotherClass implements Example {
    private Example example = new DefaultClassImpl();

    @Override
    public void method1() {
          this.example.method1();
    }

    @Override
    public String method2(final int parameter) {
          return this.example.method2(parameter);
    }
}

【讨论】:

  • 如果使用接口的类已经是子类怎么办。然后我们不能使用抽象类,因为不支持多重继承。 @m0skit0
  • @xtreak 听起来像是一个糟糕的对象层次结构
  • 谢谢我明白了。我可以在 AnotherClass 中使用一个方法来实例化 InnerExampleImpl。有必要在AnotherClass中有接口吗?同样对于每个实现接口的类,我是否必须设计一个内部类? @m0skit0
  • +1 在 java 8 中,接口可以有方法的默认实现。
  • 它在 java 8 @m0skit0 中可用。但感谢您的洞察力。
【解决方案2】:

您可以创建一个抽象类实现该接口,并使您的这些类继承抽象类,这应该是你想要的。

【讨论】:

  • 您是建议将类作为接口?如果我已经将实现接口的类作为子类实现了呢?
  • 不,我是说你添加了一个新的抽象类来实现你的接口,在这个抽象类中你提供了通用的实现。然后在你的 100 个类中(都继承这个抽象类),你可以让其中的 30 个覆盖那个实现,而其他的只使用那个通用的实现。
  • 如果实现接口的类已经是子类怎么办。由于多重继承,抽象类无法使用@Paul
  • 不,这不是问题,因为它不是“多重继承”的情况。这就是接口的灵活性之美,实现与扩展完全不冲突。您可以让一个类扩展另一个类(继承),同时实现多个接口。
  • 对于您担心的情况,我认为@m0skit0 已经包含在他的答案和 cmets 中 :)
【解决方案3】:

实现和接口的非抽象类需要实现接口中的所有方法。抽象类不必实现所有方法但不能初始化。如果您在示例中创建实现除一个之外的所有接口方法的抽象类。从这些抽象类扩展而来的类只需要实现一个尚未实现的方法。

【讨论】:

  • Java 不支持多重继承,我们有接口来实现它们。所以当我需要使用两个类时,我使用一个类和一个接口。如果我需要两个类和多重继承怎么办?
  • 多次单继承:class A implements I1{} class B extends class A implements I2{}
【解决方案4】:

Java 接口可以被称为 contracts 来更好地传达他们的意图。声明者承诺提供一些功能,而使用代码保证对象提供该功能。

这是一个强大的概念,并且与 如何 在 Java 有点受限并且您不是第一个注意到这一点的情况下提供功能分离。我个人发现很难提供只需要一个或两个子类就可以在给定情况下使用的“完美”实现。 Swing 使用适配器来提供空实现,然后可以根据需要对其进行覆盖,这可能是您正在寻找的技术。

【讨论】:

    【解决方案5】:

    接口的想法是创建一系列足够抽象的方法,以供实现它们的不同类使用。该概念基于 DRY 原则(不要重复自己),接口允许您拥有 run() 之类的方法,这些方法足够抽象,可用于游戏循环、玩家运行能力,

    【讨论】:

    • 当我使用带有通用代码的接口并在必要时覆盖它时,它更加有助于 DRY 原则。定义一个通用代码 70 次不违反 DRY 有什么意义?
    【解决方案6】:

    你应该先了解接口的基础。这是

    • 它是用来提供紧耦合手段紧封装
    • 它帮助我们将代码隐藏在外部环境中,即其他类中
    • 接口应该只有常量的定义和数据
    • 它为开放类扩展提供了便利。因此它不能被java中的任何其他类替换,否则该类将变得关闭以进行扩展。这意味着类将无法扩展任何其他类。

    【讨论】:

      【解决方案7】:

      我认为您最关心的是面向对象设计的概念。在上面的示例中,您声明您有 100 类和 70 其中的类具有相同的方法实现(我会对此感到震惊)。所以给定一个这样的界面:

      public interface Printable
      {    
           void print();
      }  
      

      还有两个具有print“相同”实现的类

      public class First implements Printable
      {  
         public void print()  
         {  
               System.out.println("Hi");
         }  
      }
      public class Second implements Printable
          {  
             public void print()  
             {  
                   System.out.println("Hi");
             }  
          }
      

      你会想要这样做:

      public abstract class DefaultPrinter implements Printable  
      {  
           public void print()  
           {  
               System.out.println("Hi");
           }  
      }
      

      现在 FirstSecond

      public class First extends DefaultPrinter 
      {  
      }
      public class Second extends DefaultPrinter
      {  
      }
      

      现在这两个仍然是 Printable 。现在,了解如何正确设计对象层次结构变得非常重要。如果某些东西不是DefaultPrinter你不能也不应该让新类扩展DefaultPrinter

      【讨论】:

      • 可以说这些类已经扩展了一个类,如 power,即 First,Second。其中一些以粗体打印,一些以斜体打印,其中 70 个带有下划线。我有一个具有 PrintStyle() 方法的通用接口。为什么我不能在接口中有一个通用的 PrintStyle() 方法,然后在需要的地方用带下划线的默认实现覆盖。
      • @xtreak 因为这不是 java 的工作方式。我在上面的回答中详细说明了如何完成您所需要的。
      • @xtreak 明确一点,抽象类是一个软件接口,所以你可以像上面一样把它放在抽象类中。
      猜你喜欢
      • 2011-08-04
      • 2022-01-01
      • 2016-12-02
      • 2014-03-19
      • 1970-01-01
      • 2016-06-14
      • 1970-01-01
      • 2021-11-02
      • 2012-09-01
      相关资源
      最近更新 更多