2012-09-21 87 views
2

我有類似:帶通配符,基類和子類的Java泛型的問題

List<? extends BaseClass> a = getMyList(); 

凡有下列兩個指令是無效的,而編譯器說,它需要一個「擴展BaseClass的?」作爲一個論據。

a.add(new BaseClass()); 
a.add(new SubClass()); 

我想這個問題是

這又如何解決呢?

+0

哪一行編譯器指向說它需要一個'?擴展BaseClass'? – Vikdor

+2

請參閱此處接受的答案:http://stackoverflow.com/questions/11781429/adding-elements-to-list-extends-superclass-clarification-needed – Natix

回答

2

問題是編譯器無法確定列表的實際類型。

可能是該類型爲​​,在這種情況下,您將不被允許添加BaseClass
它甚至可能是SubSubClass,這意味着您不能添加BaseClass或​​。

然而,這將編譯:

List<BaseClass> a = getMyList(); 
a.add(new BaseClass()); 
a.add(new SubClass()); 
1

一般的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示例中,因爲即使泛型主要添加到集合中,它們也是語言功能,所以您必須瞭解它們所承載的語義,而不是集中在容器類型的特定實現上。