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

adi*_*tsu 5 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");
    }
}
Run Code Online (Sandbox Code Playgroud)

SingleTask我提供用于方法的实现getsize,它们是从仅抽象方法AbstractList.但是,当我编译时MyTask,我仍然会遇到如下错误:

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

要么

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

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

所以我有两个问题:

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

biz*_*lop 6

强制SingleTask实现者也实现所有方法List都不是很优雅,并且默认方法不能用于定义类似特征的实体,您的SingleTask界面看起来就像.

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

这正是这里发生的事情:因为AbstractList显式声明get()size()as abstract,它意味着SingleTask将继承它们,而不是你在超级接口中可能拥有的默认实现.

JLS 8.4.8:

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

...

  • C从其直接超类继承的具体方法没有签名,该签名是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();
}
Run Code Online (Sandbox Code Playgroud)

它的缺点是你的任务必须扩展SingleTask,因此不能扩展任何其他东西,虽然他们不需要处理任务也是一个优点List,他们只需要实现run().

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