使用方法参数超类的接口实现
作为主题中一般问题的一个实际示例,我想在 Set
接口中实现 containsAll
方法,
public boolean containsAll(Iterable<?> c) { /* ... */ }
我认为应该允许这样做,因为 Collection
是 Iterable
意味着这样的 containsAll
将满足接口要求。同样,更一般地说,能够使用参数超类实现接口似乎应该可行。
然而,Eclipse 说没办法(没有直接尝试过 javac)——有人能解释一下原因吗?我确信规范中有一些东西使它成为现在的样子,但我也想了解需求的动机。或者我是否缺少诸如 Iterable
之类的东西,而不是 Collection
的超类?
作为一个附带问题 - 假设我声明了两种方法,在使用 Collection
参数进行调用时,是否始终会首选具有 Iterable
签名的方法?
Eclipse 错误:
如果我删除带有 Collection
签名的方法,只留下 Iterable
一个(参见错误后),我会得到以下信息:
The type BitPowerSet must实现继承的抽象方法 Set
具体实现是:
@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;
}
As a practical example of the general question in the subject, I'd like to implement the containsAll
method in the Set
interface with
public boolean containsAll(Iterable<?> c) { /* ... */ }
I figure this should be allowed, since Collection
is Iterable
meaning such a containsAll
would cover the interface requirement. Likewise, more generally being able to implement interfaces with argument superclasses seems like it should work.
However, Eclipse says no way (haven't tried just javac straight-up) - can someone explain the reason for that? I'm sure there's something in the spec which makes it the way it is, but I'd like to understand the motivation for requirement as well. Or am I missing something like Iterable<?>
not being a superclass of Collection<?>
?
As a side question - given I'm declaring two methods would the method with the Iterable
signature always be preferred on calls with a Collection
argument?
Eclipse Error:
If I remove the method with the Collection
signature, just leaving the Iterable
one (see after error), I get the following:
The type BitPowerSet must implement the inherited abstract method Set<Long>.containsAll(Collection<?>)
The exact implementation being:
@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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
由于您要实现的接口声明了(抽象)方法
containsAll(Collection)
,因此您必须使用这个确切的签名来实现它。 Java 不允许您实现/重写具有比原始参数类型更广泛的参数类型的方法。这就是为什么当您使用Collection
签名注释掉您的方法时会出现错误。您没有显示您声称在未注释掉该方法时遇到的其他错误,但我想它可能必须通过不明确的方法重载来执行某些操作。
Since the interface you are implementing declares the (abstract) method
containsAll(Collection<?>)
, you must implement it with this exact signature. Java does not allow you to implement/override a method with a wider parameter type than the original. This is why you get the error you show when you comment out your method with theCollection
signature.You don't show the other error you claim to get when the method is not commented out, but I guess it might have to do something with ambiguous method overloading.
我对为什么java有这个限制的猜测是,假设你有:
现在,如果你有
class C extends B
并且它想要覆盖foo
,则不清楚它的参数是什么应该采取。例如,C 首先直接扩展 A,覆盖
void foo(String s)
,然后将其更改为扩展 B。在这种情况下,C 现有的foo
覆盖将是变得无效,因为 B 的foo
应该能够处理所有Object
,而不仅仅是String
。My guess as to why java has this restriction is, say you have:
Now if you have
class C extends B
and it wants to overridefoo
, it's not clear what argument it should take.Say for example C extended A directly at first, overriding
void foo(String s)
, and then it was changed to extend B. In this case C's existing override offoo
would become invalid because B'sfoo
should be able to handle allObject
s, not justString
s.参数类型是方法签名的一部分,因此 jvm 需要一个具有完全相同签名的方法来查找重写。 containsAll(Iterable) 将具有与 containsAll(Collection) 不同的签名。
如果我没记错的话,编译器必须使用一些解决方法来使泛型工作,尽管有这个限制。
对于第二个问题,编译器更喜欢 Collection 参数,因为它是 Iterable 的子类型,这使得 Collection 方法比 Iterable 方法更具体。
The argument types are part of the method signature so the jvm needs a method with exact the same signature to find overrides. A containsAll( Iterable) will have a different signature than containsAll(Collection).
If I remember right the compiler has to use some workarounds to make generics work in spite of this limitation.
To your second question, the compiler would prefer the Collection argument since it is a subtype of Iterable, this makes the Collection method more specific than the Iterable one.