作为主题中一般问题的实际示例,我想在containsAll
界面中实现Set
方法
public boolean containsAll(Iterable<?> c) { /* ... */ }
我认为这应该被允许,因为Collection
是Iterable
意味着这样的containsAll
将覆盖接口要求。同样,更一般地说,能够实现与参数超类的接口似乎应该可以工作。
然而,Eclipse说没有办法(没有尝试过javac直播) - 有人可以解释原因吗?我确信规范中的某些内容使其成为现实,但我也想了解需求的动机。或者我错过了Iterable<?>
不是Collection<?>
的超类?
作为一个附带问题 - 鉴于我正在声明两种方法,带有Iterable
签名的方法在带有Collection
参数的调用中总是首选吗?
如果我删除带有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;
}
答案 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更具体。