以下是显示我的问题的简化示例:
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
中,我提供了方法get
和size
的实现,这是AbstractList
中唯一的抽象方法。但是,当我编译MyTask
时,我仍然会收到如下错误:
MyTask类型必须实现继承的抽象方法 AbstractCollection.size()
或
MyTask.java:3:错误:MyTask不是抽象的,并且不会覆盖AbstractList中的抽象方法get(int)
(取决于编译器)。我当然是使用java 8。
所以我有两个问题:
MyTask
中使用这两种方法而不复制整个代码的最简单方法是什么?答案 0 :(得分:6)
强制SingleTask
实现者也实现List
的所有方法都不是很优雅,并且默认方法不能用于定义类似特征的实体,你的{{1接口看起来像。
默认方法作为特征是一个坏主意有几个原因,最明显的是任何实现者都可以简单地覆盖你的默认方法,破坏你的特性。
这正是这里发生的事情:因为SingleTask
明确地将AbstractList
和get()
声明为size()
,这意味着abstract
会继承它们,而不是比你在超级接口中可能有的默认实现。
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)
- 为什么我会收到这些错误?我期待它能够识别默认的实现。
醇>
我认为@biziclop在his answer中正确地涵盖了这一点。简而言之,由于AbstractList
将get(int)
和size()
方法声明为抽象,因此这些方法优先于SingleTask
中的默认实现。
- 如果它不应该那样工作,那么在
醇>MyTask
中使用这两种方法而不复制整个代码的最简单方法是什么?
最简单的方法是覆盖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
中的默认方法。我不认为这是一件坏事(至少,你不需要使用属性)。此外,编写这些方法是有意义的,这样您就可以选择哪个接口提供默认实现。