使用方法参数超类的接口实现

时间:2010-10-16 16:06:46

标签: java interface method-signature

作为主题中一般问题的实际示例,我想在containsAll界面中实现Set方法

public boolean containsAll(Iterable<?> c) { /* ... */ }

我认为这应该被允许,因为CollectionIterable意味着这样的containsAll将覆盖接口要求。同样,更一般地说,能够实现与参数超类的接口似乎应该可以工作。

然而,Eclipse说没有办法(没有尝试过javac直播) - 有人可以解释原因吗?我确信规范中的某些内容使其成为现实,但我也想了解需求的动机。或者我错过了Iterable<?>不是Collection<?>的超类?

的内容

作为一个附带问题 - 鉴于我正在声明两种方法,带有Iterable签名的方法在带有Collection参数的调用中总是首选吗?

<\ n> Eclipse错误:

如果我删除带有Collection签名的方法,只需离开Iterable一个(请参阅错误后),我会得到以下内容:

The type BitPowerSet must implement the inherited abstract method Set<Long>.containsAll(Collection<?>)

确切的实施是:

@Override public boolean containsAll(Collection<?> c) {
  for (Object o : c) if (!contains(o)) return false;
  return true;
}
public boolean containsAll(Iterable<?> c) {
  for (Object o : c) if (!contains(o)) return false;
  return true;
}

3 个答案:

答案 0 :(得分:5)

由于您正在实现的接口声明了(抽象)方法containsAll(Collection<?>),因此您必须使用此确切签名来实现它。 Java不允许您使用比原始参数类型更宽的参数类型来实现/覆盖方法。这就是为什么当您使用Collection签名注释掉您的方法时,您会收到错误。

当没有注释掉该方法时,您没有显示您声称获得的其他错误,但我想它可能需要对模糊方法重载执行某些操作。

答案 1 :(得分:2)

我猜测为什么java有这个限制,比如你有:

class A {
    void foo(String s) { ...  }
}

class B extends A {
    // Note generalized type
    @Override void foo(Object s) { ...  }
}

现在,如果您有class C extends B并且想要覆盖foo,则不清楚它应该采用什么参数。

比如说,例如C首先直接扩展A,覆盖void foo(String s),然后将其更改为扩展B.在这种情况下,C的现有覆盖foo将变为无效,因为B {{1}应该能够处理所有foo,而不仅仅是Object

答案 2 :(得分:0)

参数类型是方法签名的一部分,因此jvm需要一个具有完全相同签名的方法来查找覆盖。 containsAll(Iterable)将具有与containsAll(Collection)不同的签名。

如果我没记错的话,编译器必须使用一些变通方法来使泛型工作尽管有这种限制。

对于第二个问题,编译器更喜欢Collection参数,因为它是Iterable的子类型,这使得Collection方法比Iterable更具体。