2010-10-16 94 views
6

如在本一般性问题的一个实际的例子,我想实现在Set接口containsAll接口实现与方法参数超

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

我想这应该是允许的,因为CollectionIterable这意味着这样的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; 
} 
+0

你可以发布Eclipse给你的错误吗?在IDEA中为我工作。 – 2010-10-16 16:11:07

+0

@Nikita:编辑。soooo ...它可能只是一个Eclipse的东西? – Carl 2010-10-16 16:15:25

+0

这是一个术语噩梦。我逃避了这些挑战。 – skaffman 2010-10-16 16:27:03

回答

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的foo应该能够处理所有Object S,不只是String s。

+0

啊,这似乎是一个明智的解释 - 扩大接口将要求子类保持扩大接口。不过,这似乎应该允许 - 通常,子类不允许缩小接口。 – Carl 2010-10-16 16:42:50

+0

它也可能使虚拟表的设计更清晰,以确定其中的所有方法都具有确切的签名。或者,他们可能只是认为如果他们足够强调,他们就可以实现这一目标,但没有看到令人信服的需求并将其排除在外。 – oksayt 2010-10-16 16:48:32

+0

我错过了一些东西 - 这个例子应该工作吗?在@Override注释中,我得到“方法不会从它的超类覆盖方法”。 – Amalgovinus 2016-06-08 19:17:13

5

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

当方法没有被注释掉时,你不会显示你声称获得的另一个错误,但我想它可能必须做一些含糊不清的方法重载。

+0

该方法未被注释掉时没有错误。只有具有“收集”签名的人才是。 – Carl 2010-10-16 16:40:43

+0

另外,任何有关为什么这种情况的见解?是否符合@ oksayt的答案? – Carl 2010-10-16 16:46:10

+0

@Carl,你的意思是为什么Java被设计成这样?可能。 – 2010-10-16 19:00:45

0

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

如果我记得正确的话,编译器必须使用一些解决方法来使泛型尽管有此限制。

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