接口中的默认方法

时间:2018-08-22 13:01:42

标签: java default-method

一段时间以来,我一直对为什么我们需要接口中的默认方法感到困惑,今天我正在阅读它。即使我的问题很少回答,我仍然有一些疑问。

让我们举一个简单的例子,我有一个interface1。 A类和B类实现interface1。 interface1具有方法X。

interface interface1{
    void methodX();
}

class A implements interface1{
   @override
   public void methodX(){
      //something 
  };
}

class B implements interface1{
   @override
   public void methodX(){
      //something 
  };
}

据我了解,由于向interface1添加新方法Y将破坏A类和B类,因此引入了默认方法。这意味着现在我可以添加一个默认方法,而无需修改A类和B类。这也意味着该默认方法必须具有足够的通用性,才能对A类和B类都执行我们期望的操作。

现在,让我们考虑一下,我们通常在接口中添加函数,以便我们可以通过重写功能为它们提供特定于类的实现。因此,基本上,如果我在默认情况下在接口中添加方法Y,则我希望类A和类B(或类A / ClassB)重写该方法。

这意味着,我将同时修改A类/ B类或两者。

这就是令我困惑的地方。可以通过创建一个新接口并修改1个(或两个)类以实现该新接口(接口2扩展interface1),然后在该类中为该接口提供实现来解决此问题。

interface interface2 extends interface1{
     void methodY();
}

class A implements interface2{
     @override
     public void methodY(){
         //something
     }
}

class B implements interface1{
   @override
   public void methodX(){
      //something 
  };
}

默认方法实际上如何帮助我们不修改实现它的类。

4 个答案:

答案 0 :(得分:2)

默认方法提供某些行为的“基础”实现,这些行为可以由给定接口上的现有方法组成。例如,您有一个使用add方法的接口。这足以为addAll行为提供默认实现:

default void addAll(Collection<? extends E> c) { for (E e : c) { add(e); } } 

另一个示例可以是List中的sort方法,可以通过以下提供的方法来实现:get(int)set(int,E)size()。子类可能会覆盖此默认实现,以便基于特定列表属性提供更有效的排序。在LinkedList中,您可以利用附加/分离节点的优势(在插入或删除节点时无需在右侧移动元素),在ArrayList中,您可以利用对任何索引的元素的超快速访问)。

答案 1 :(得分:1)

由于在接口中定义了默认方法,因此它只能访问也在同一接口中定义的实例方法。因此,它只能调用实现类实际提供的功能(在您的示例AB中)。

默认方法不会“更改”类的行为,而是通过访问现有的,正确定义的行为来扩展它。

答案 2 :(得分:1)

如果您强制所有实现类覆盖新方法,则它(如果没有有效的默认实现)应该不是默认方法。

但是,您刚才所说的方法是创建一个扩展现有接口的新接口,并通过更改实现的接口类型,使希望的类覆盖新方法由于新方法是新接口的一部分,因此会出现问题,如果您具有父/基本接口类型,则无法访问它。

示例:

现有代码:

interface Base {
    void m1();
}
class A implements Base {
   @Override
   public void m1() {
      ....
   }
}
class B implements Base {
   @Override
   public void m1() {
      ....
   }
}

您创建以下界面

interface ExtendedBase extends Base {
    void m2();
}

只有类A要实现m2。因此,它变成了

class A implements ExtendedBase {
   @Override
   public void m1() {
      ....
   }
   @Override
   public void m2() {
      ....
   }
}

到目前为止一切都很好。

如果您的方法使用的对象类型为Base,则只能在其上调用m1(无论您传递的对象类型为A还是B

void someMethod(Base base) {
    base.m1();
    //base.m2(); won't work
}

要在其他地方实际使用m2,您需要将Base更改为ExtendedBase,这意味着您无法再将B传递给它。因此,无论如何,您已经使所有类都实现了m2

答案 3 :(得分:1)

  

因此,基本上,如果我默认在接口中添加方法Y,那么我期望类A和类B(或类A / ClassB)将覆盖该方法。

这是错误的。

默认方法的想法是引入新方法,而不会与旧代码兼容。

现有的实现类无需修改即可使用新的默认方法。

  

这可以通过创建一个新接口并修改1个(或两个)类以实现该新接口(接口2扩展interface1),然后在该类中为该接口提供实现来解决。

然后,您必须触摸/修改实现类。这就是default方法要避免的方法。