我有類似:帶通配符,基類和子類的Java泛型的問題
List<? extends BaseClass> a = getMyList();
凡有下列兩個指令是無效的,而編譯器說,它需要一個「擴展BaseClass的?」作爲一個論據。
a.add(new BaseClass());
a.add(new SubClass());
我想這個問題是
這又如何解決呢?
我有類似:帶通配符,基類和子類的Java泛型的問題
List<? extends BaseClass> a = getMyList();
凡有下列兩個指令是無效的,而編譯器說,它需要一個「擴展BaseClass的?」作爲一個論據。
a.add(new BaseClass());
a.add(new SubClass());
我想這個問題是
這又如何解決呢?
問題是編譯器無法確定列表的實際類型。
可能是該類型爲,在這種情況下,您將不被允許添加BaseClass
。
它甚至可能是SubSubClass
,這意味着您不能添加BaseClass
或。
然而,這將編譯:
List<BaseClass> a = getMyList();
a.add(new BaseClass());
a.add(new SubClass());
它應該是List<? super BaseClass> a
添加到它的東西。你只能從List<? extends BaseClass> a
獲得東西。
一般的Java教程說你不能添加任何東西到List<? extends Something>
因爲編譯器無法知道在列表中的有效類型。
我發現這個解釋不直觀,也並不完全正確,因爲它假裝編譯器是智能的存在,它的理解是一個List
是元素的有序的容器,並阻止你做可能不安全的事情。實際上,編譯器只是一個程序,它只是服從一些規則。
所以,最好做一些角色扮演,並像編譯器一樣思考。你有
interface List<E> {
void add(E element);
}
注意<E>
不向編譯器提供任何額外的語義,在某種意義上說,它不知道你要定義一個容器類型。你可以定義一個Asdf<Q>
,對於編譯器來說不重要,或者是一個Elephant<W>
,並且仍然適用相同的規則(並且明顯的Elephant
不是容器類型,即,你不會向大象添加任何東西 - 我希望.. )
因此,您聲明瞭類型爲List<? extends Shape>
的參考。編譯器理解類似
abstract class Unknown extends Shape {}
class ListOfUnknown {
void add(Unknown element) {}
Unknown get(int index) {}
}
你可以看到爲什麼你不能一個Rectangle
添加到這樣的列表的東西嗎?根據正常的 Java規則,你可以提供一個Rectangle
的方法,如add(Shape)
,因爲它們的接口通過子類型關係被保證是兼容的。
被允許調用add(Unknown)
與Rectangle
類型的參數,Rectangle
應該是Unknown
一個孩子,但Rectangle
僅延Shape
,所以沒有什麼特別的仿製藥在這裏,它是類型兼容普通的Java規則。爲了能夠撥打add(Unknown)
,您需要參考Unknown
類型的對象(某些類別可以擴展爲Unknown
),但正如您所看到的,在任何地方都沒有定義此類型,因此最終會禁止add()
任何內容名單。
在學習仿製藥時,總是問自己「爲什麼?並且從未停止在List
示例中,因爲即使泛型主要添加到集合中,它們也是語言功能,所以您必須瞭解它們所承載的語義,而不是集中在容器類型的特定實現上。
哪一行編譯器指向說它需要一個'?擴展BaseClass'? – Vikdor
請參閱此處接受的答案:http://stackoverflow.com/questions/11781429/adding-elements-to-list-extends-superclass-clarification-needed – Natix