这是一个显示我的问题的简化示例:
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
时,我仍然会遇到如下错误:
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。
所以我有两个问题:
- 为什么会出现这些错误?我期待它能够识别默认实现。
- 如果它不应该那样工作,那么在
MyTask
中使用这两个方法而不复制整个代码的最简单方法是什么?
最佳答案
强制 SingleTask
实现者也实现 List
的所有方法不是很优雅,并且默认方法并不意味着用于定义类似特征的实体,您的 SingleTask
界面看起来像这样。
将默认方法作为特征作为一个坏主意的原因有很多,最明显的一个是任何实现者都可以简单地覆盖您的默认方法,从而破坏您的特征。
这正是这里发生的事情:因为 AbstractList
明确声明 get()
和 size()
为 abstract
,这意味着 SingleTask
将继承它们,而不是您在 super 接口(interface)中可能拥有的默认实现。
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()
。
但从长远来看,我更喜欢组合而不是继承,任务只是返回一个可运行对象列表而不是它们本身就是一个。
关于java - 必须实现默认接口(interface)方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35770017/