Java 8错误:接口继承抽象和默认值

Java 8错误:接口继承抽象和默认值,java,interface,java-8,Java,Interface,Java 8,我试图编写一个集合接口库,使用Java8中新的默认方法语法实现标准集合API中的大多数方法。以下是我想要的一个小样本: public interface MyCollection<E> extends Collection<E> { @Override default boolean isEmpty() { return !iterator().hasNext(); } //provide more default override

我试图编写一个集合接口库,使用Java8中新的默认方法语法实现标准集合API中的大多数方法。以下是我想要的一个小样本:

public interface MyCollection<E> extends Collection<E> {
    @Override default boolean isEmpty() {
        return !iterator().hasNext();
    }
    //provide more default overrides below...
}

public interface MyList<E> extends MyCollection<E>, List<E> {
    @Override default Iterator<E>iterator(){
        return listIterator();
    }
    //provide more list-specific default overrides below...
}
公共接口MyCollection扩展了集合{
@重写默认布尔值isEmpty(){
return!迭代器().hasNext();
}
//在下面提供更多默认覆盖。。。
}
公共接口MyList扩展了MyCollection,List{
@重写默认迭代器(){
返回listIterator();
}
//在下面提供更多特定于列表的默认覆盖。。。
}
但是,即使是这个简单的示例也会遇到编译器错误:

error: interface MyList<E> inherits abstract and default
       for isEmpty() from types MyCollection and List
错误:接口MyList继承抽象和默认值
对于类型MyCollection和List中的isEmpty()
根据我对默认方法的理解,这应该是允许的,因为只有一个扩展接口提供了默认实现,但显然不是这样。这是怎么回事?有没有一种方法可以让它实现我想要的功能?

这在Java语言规范的一部分中进行了解释:

接口可以继承多个具有覆盖等效签名的方法(§8.4.2)

类似地,当继承了具有匹配签名的抽象和默认方法时,我们会产生一个错误。在这种情况下,可能会优先考虑其中一个——也许我们会假设默认方法也为抽象方法提供了合理的实现。但这是有风险的,因为除了巧合的名称和签名之外,我们没有理由相信默认方法的行为与抽象方法的契约一致——默认方法可能在最初开发子接口时根本不存在在这种情况下,要求用户主动断言默认实现是适当的(通过覆盖声明)更安全。

因此,由于
MyCollection
List
都定义了一个方法
isEmpty()
,一个是默认的,另一个是抽象的,编译器要求子接口通过再次重写该方法显式声明它应该继承的方法。如果希望继承默认方法
MyCollection
,则可以在覆盖实现中调用它:

public interface MyList<E> extends MyCollection<E>, List<E> {
    @Override default boolean isEmpty() {
        return MyCollection.super.isEmpty();
    }

    @Override default Iterator<E> iterator(){
        return listIterator();
    }
    ...
}

将源代码更改为

public interface MyList<E> extends MyCollection<E>,List<E> {
     @Override 
     default boolean isEmpty(){
           return MyCollection.super.isEmpty();
      }
}
公共接口MyList扩展了MyCollection,List{
@凌驾
默认布尔值为空(){
返回MyCollection.super.isEmpty();
}
}
有关更多信息,请点击链接,

复制所有这些方法签名的需要令人失望,但这似乎正是我想要的。接受,假设没有办法避免这一点。它真正的缺点是没有理由重新声明
isEmpty()
。它的唯一目的似乎是将文档注释从继承的“如果此集合不包含元素,则返回true”更改为更具体的“如果此列表不包含元素,则返回true”。如果没有此注释,一切都会像以前一样工作,但是这个问题产生的编译错误会消失,因为
MyCollection.isEmpty()
overrides
Collection.isEmpty()
…@Holger在这种情况下你是对的。但对于其他方法,如
toArray
,文档在方法契约方面的差异更大。我认为这个问题是使用默认方法的代价。这看起来也类似于多重继承的钻石问题。@Holger这是一个很好的例子,“显然正确”的答案被证明是错误的。考虑到这样的简单冲突,抽象的默认冲突应该以有利于默认的方式解决似乎是“显而易见的”(事实上,我们就是从这里开始的)。然而,随着层次结构变得越来越复杂,“显而易见”的事情从不那么明显到混乱再到近乎怪异,并开始要求使用更复杂的工具来解决冲突,而这反过来又会带来非常低的复杂性回报。手动解决此类冲突要简单得多——这并不难。调用
MyCollection.super.isEmpty()
是多余的
public interface MyList<E> extends MyCollection<E>,List<E> {
     @Override 
     default boolean isEmpty(){
           return MyCollection.super.isEmpty();
      }
}