Java 8 错误:接口继承抽象和缺省

2022-09-04 21:53:36

我正在尝试编写一个集合接口库,这些库使用 Java 8 中新的默认方法语法实现标准集合 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...
}

但是,即使这个简单示例也会遇到编译器错误:

error: interface MyList<E> inherits abstract and default
       for isEmpty() from types MyCollection and List

根据我对默认方法的理解,这应该是允许的,因为只有一个扩展接口提供默认实现,但显然情况并非如此。这是怎么回事?有没有办法让它做我想做的事?


答案 1

Java 语言规范的第 9.4.1.3 节(使用覆盖等效签名继承方法)对此进行了解释:

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

...

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

因此,由于同时定义一个方法,一个是默认的,另一个是抽象的,编译器要求子接口通过再次重写该方法来显式声明它应该继承哪一个。如果您希望继承 默认方法 ,则可以在重写实现中调用它:MyCollectionListisEmpty()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();
    }
    ...
}

如果你想保留摘要(我认为你不想要),你可以这样做:MyListisEmpty()

public interface MyList<E> extends MyCollection<E>, List<E> {
    @Override boolean isEmpty();

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

答案 2

将源代码更改为

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

有关更多信息,请访问链接,界面中的默认实现