必须实现默认接口方法吗?

时间:2016-03-03 10:47:57

标签: java java-8 default-method

以下是显示我的问题的简化示例:

import java.util.List;

public interface SingleTask extends List<Runnable>, Runnable {
    default Runnable get(final int x) {
        if (x != 0) {
            throw new IndexOutOfBoundsException();
        }
        return this;
    }

    default int size() {
        return 1;
    }
}

import java.util.AbstractList;

public class MyTask extends AbstractList<Runnable> implements SingleTask {
    @Override
    public void run() {
        System.out.println("hello");
    }
}

SingleTask中,我提供了方法getsize的实现,这是AbstractList中唯一的抽象方法。但是,当我编译MyTask时,我仍然会收到如下错误:

  

MyTask类型必须实现继承的抽象方法   AbstractCollection.size()

  

MyTask.java:3:错误:MyTask不是抽象的,并且不会覆盖AbstractList中的抽象方法get(int)

(取决于编译器)。我当然是使用java 8。

所以我有两个问题:

  1. 为什么我会收到这些错误?我期待它能够识别默认的实现。
  2. 如果它不应该那样工作,那么在MyTask中使用这两种方法而不复制整个代码的最简单方法是什么?

2 个答案:

答案 0 :(得分:6)

强制SingleTask实现者​​也实现List的所有方法都不是很优雅,并且默认方法不能用于定义类似特征的实体,你的{{1接口看起来像。

默认方法作为特征是一个坏主意有几个原因,最明显的是任何实现者都可以简单地覆盖你的默认方法,破坏你的特性。

这正是这里发生的事情:因为SingleTask明确地将AbstractListget()声明为size(),这意味着abstract会继承它们,而不是比你在超级接口中可能有的默认实现。

JLS 8.4.8

  

C类继承自其直接超类和直接   对所有抽象和默认(§9.4)方法m进行超级接口   以下所有都是真的:

     

...

     
      
  • C从其直接超类继承的具体方法没有签名,该签名是m的签名的子签名。
  •   

考虑到所有这些,最简单的解决方案可能就是:

SingleTask

它的缺点是你的任务必须扩展public abstract class SingleTask extends AbstractList<Runnable> implements Runnable { @Override public final Runnable get(final int x) { if (x != 0) { throw new IndexOutOfBoundsException(); } return this; } @Override public final int size() { return 1; } @Override public abstract void run(); } ,因此不能扩展任何其他东西,虽然他们不需要处理任务SingleTask,他们也不能扩展其他任何东西。只需要实现List

从长远来看,我更喜欢组合而不是继承,而任务只是返回一个runnables列表,而不是自己是一个。

答案 1 :(得分:2)

  
      
  1. 为什么我会收到这些错误?我期待它能够识别默认的实现。
  2.   

我认为@biziclop在his answer中正确地涵盖了这一点。简而言之,由于AbstractListget(int)size()方法声明为抽象,因此这些方法优先于SingleTask中的默认实现。

  
      
  1. 如果它不应该那样工作,那么在MyTask中使用这两种方法而不复制整个代码的最简单方法是什么?
  2.   

最简单的方法是覆盖get(int)中的size()MyTask方法,以便他们委托SingleTask界面中的默认方法:

public class MyTask extends AbstractList<Runnable> implements SingleTask {

    @Override
    public void run() {
        System.out.println("hello");
    }

    @Override
    public Runnable get(int index) {
        return SingleTask.super.get(index);
    }

    @Override
    public int size() {
        return SingleTask.super.size();
    }
}

使用这种方法,您可以委派SingleTask中的默认方法。我不认为这是一件坏事(至少,你不需要使用属性)。此外,编写这些方法是有意义的,这样您就可以选择哪个接口提供默认实现。