2010-10-16 140 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更具體。