[英]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.