2016-03-03 137 views
5

在这里是表示我的问题的简化示例:必须实现默认的接口方法吗?

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,我还是得到这样的错误:

The type MyTask must implement the inherited abstract method AbstractCollection.size()

MyTask.java:3: error: MyTask is not abstract and does not override abstract method get(int) in AbstractList

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

所以我有两个问题:

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

不要让你的任务扩展'List '(这意味着什么意思,语义无论如何?),而是创建一个接口'任务'与'公共列表 getRunnables();'方法。否则,只需将SingleTask作为抽象类而不是接口即可。 – biziclop

+1

值得注意的是Eclipse没有实现'size()',这可能是Eclipse的一个bug。 'javac' 1.8.0_51扼杀了'get(int)'没有被执行,它是正确的:它没有被实现。 – Tunaki

+0

@biziclop它应该是一个任务清单; SingleTask是一个单例实现 – aditsu

回答

6

强制SingleTask实现者,也能实现的List所有方法是不是很优雅,但并不意味着默认方法可以用来定义特质样的实体,你的SingleTask界面的样子。

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

而这正是这里发生了什么:因为AbstractList显式声明get()size()abstract,这意味着SingleTask将继承他们,而不是你可能有一个超接口的默认实现。

JLS 8.4.8

A class C inherits from its direct superclass and direct superinterfaces all abstract and default (§9.4) methods m for which all of the following are true:

...

  • No concrete method inherited by C from its direct superclass has a signature that is a subsignature of the signature of m.

轴承都考虑到这一点最简单的解决方案可能是这样的:

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的任务,但他们只需要实现run()

但是从长远来看,我宁愿将构造视为继承,而只是简单地返回可运行列表的列表,而不是其自身。

+0

我并不强迫SingleTask实现者也扩展AbstractList,但它看起来像你。此外,你让SingleTask成为一个类,这意味着如果我想使用它,我不能扩展一个不同的类。而且你甚至没有试图回答我的第一个问题。 – aditsu

+1

@aditsu'我并没有强迫SingleTask实现者扩展AbstractList'是的,你确实是这样,这就是导致问题的原因。我会编辑我的答案以涵盖这一点。 – biziclop

+0

错误,用我的代码,SingleTask实现者只需要实现List的方法。 SingleTask中没有关于AbstractList的内容! – aditsu

2
  1. Why am I getting these errors? I was expecting it to recognize the default implementations.

我认为@biziclop正确覆盖了his answer。总之,由于AbstractListget(int)size()方法声明为抽象方法,因此这些方法优先于SingleTask中的默认实现。

  1. If it's not supposed to work like that, then what's the simplest way to use those two methods in MyTask without copying the whole code?

最简单的将是覆盖MyTaskget(int)size()方法,让他们委托给您的默认方法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的默认方法。我不认为这是一件坏事(至少,你不需要使用属性)。此外,编写这些方法是有意义的,以便您可以选择提供默认实现的接口。