2013-10-04 35 views
2

我有3種簡單的類如下:泛型類型的Java - 先進的多態性

public class ElementA {} 
public class ElementB extends ElementA {} 
public class ElementC extends ElementB {} 

然後,如果我想創建,例如,泛型列表這隻需ElementA類的子類,我可以聲明爲:

list.add(new ElementA()); 
list.add(new ElementB()); 
list.add(new ElementC()); 

這是很好的,可以沒有錯誤編譯:

List<? super ElementA> list = new ArrayList<>(); 

,然後按如下方式使用它。但是,如果我想存儲任何東西,但不是ElementC或ElementB或ElementA,我就會感到困惑。我宣佈這樣的列表如下:

List<? extends ElementC> list = new ArrayList<>(); 

我完全不能使用它,因爲它只能存儲空值。同樣的事情發生時,我宣佈名單的(請注意,我使用的類,這是「在家庭中」):

List<? extends ElementB> 

爲什麼會這樣?

+2

你爲什麼期望'List <?擴展ElementC> list = new ArrayList <>();'存儲任何東西,你沒有任何擴展ElementC的類? – Chris

+0

請閱讀我的問題的結尾。我甚至用Object類試過,仍然List只能存儲空值 –

+0

'List <? extends Object> list = new ArrayList <>();'? 您應該使用如下元素初始化您的列表: 'List <?擴展ElementB> list = new ArrayList ();' – Chris

回答

3

問題是?的值在運行時是未知的。你必須替換具體的類/接口才能做到你想要的。

如果你這樣做:

List<ElementA> list = new ArrayList<ElementA>(); 

你是罰款,因爲ElementBElementA在同一時間。同樣代表ElementC

List<? extends ElementA>如果你例如在一個類和子類中聲明它,你可以用具體的東西來代替類型參數。笨拙的例子:

public class SomeClass<T> { 
    private List<? extends T> list; 

    public void setList(List<? extends T> list) { 
     this.list = list; 
    } 
} 

public class SomeConcreteClass extends SomeClass<Integer> { 

    public void doSomething() { 
     List<Integer> list = new ArrayList<Integer>(); 
     setList(list); 
    } 
} 
1

List<ElementA>接受ElementA,ElementBElement C的實例。

List<ElementB>接受ElementBElement C的實例。

List<ElementC>接受ElementC的實例。

在你的例子中沒有理由使用通配符。

List<? super ElementA>表示某種類型的列表,即ElementA或超類。

List<? extends ElementB>表示某種類型的列表,它是ElementB的一個子類。如果你得到一個元素它將是ElementB或一個子類,但它不知道類是什麼,所以它不能確定你添加的元素是正確的類型,因爲它是未知的(儘管它確實知道它是ElementB的子類)。

通配符有用途,但您的示例不是其中之一。

+0

關於'List <?超級元素A>'看看[這裏](http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#What%20is%20a%20wildcard%20instantiation?):「通配符參數化類型'比較器< ?super String>'是**類型參數類型的'Comparator'接口的所有實例的族,這些類型參數類型是'String'的**超類型**'。你似乎是在說相反的話。 – rsenna

+0

「'List <?extends ElementB>'表示某個類型的List,它是'ElementB'的子類的一個類型 - 實際上,它也可以是'ElementB'的列表;它不限於'ElementB'的_subclasses_。 –

+0

好的。在我的部分錯別字。固定。 –

0

您創建一個List這樣

List<? extends ElementC> list = new ArrayList<>(); 

但是我們要說,因爲它仍然是有效的,你得到了List這樣

List<? extends ElementC> list = getElementCSubclassList(); // declared as returning a `List<ElementCSubclass>` 

現在,編譯器無法知道您的list對象包含ElementCSubclass對象,因此只能確定它包含一些類型的ElementC。因此,它不能讓您使用任何期望實際泛型類型的方法。

想象

public class ElementCSubclass1 extends ElementC {} 
public class ElementCSubclass2 extends ElementC {} 
... 
List<? extends ElementC> list = getElementCSubclass1List(); // declared as returning a `List<ElementCSubclass1>` 

list.add(new ElementCSubclass2()); // this would immediately have to fail 

編譯器會這樣,以前永遠不會出現。