[英]Java method to accept ArrayLists of different superclasses, must use Interface?
[英]Interface implementation with method argument superclasses
作为本主题中一般问题的一个实际例子,我想在Set
接口中实现containsAll
方法
public boolean containsAll(Iterable<?> c) { /* ... */ }
我认为这应该是允许的,因为Collection
是Iterable
意味着这样的containsAll
将覆盖接口要求。 同样,更普遍的是能够实现与参数超类的接口似乎应该工作。
然而,Eclipse说没办法(没有试过直接javac) - 有人可以解释原因吗? 我确信规范中的某些内容使其成为现实,但我也想了解需求的动机。 或者我错过了像Iterable<?>
这样的东西不是Collection<?>
的超类?
作为一个附带问题 - 鉴于我正在声明两种方法,带有Iterable
签名的方法在使用Collection
参数的调用时总是首选吗?
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;
}
由于您正在实现的接口声明(abstract)方法containsAll(Collection<?>)
,因此必须使用此精确签名实现它。 Java不允许您使用比原始参数类型更宽的参数类型来实现/覆盖方法。 这就是当您使用Collection
签名注释掉方法时出现错误的原因。
当没有注释掉该方法时,您没有显示您声称获得的其他错误,但我想它可能需要对模糊方法重载执行某些操作。
我猜测为什么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的foo
应该能够处理所有Object
,不仅仅是String
。
参数类型是方法签名的一部分,因此jvm需要一个具有完全相同签名的方法来查找覆盖。 containsAll(Iterable)将具有与containsAll(Collection)不同的签名。
如果我没记错的话,编译器必须使用一些变通方法来使泛型工作尽管有这种限制。
对于第二个问题,编译器更喜欢Collection参数,因为它是Iterable的子类型,这使得Collection方法比Iterable更具体。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.