[英]Generic types in Java - advanced polymorphism
我有3個簡單的類,如下所示:
public class ElementA {}
public class ElementB extends ElementA {}
public class ElementC extends ElementB {}
然后,如果我想創建例如僅包含ElementA類的子類的通用List,則可以將其聲明為:
List<? super ElementA> list = new ArrayList<>();
然后按如下方式使用它:
list.add(new ElementA());
list.add(new ElementB());
list.add(new ElementC());
很好,可以編譯而不會出錯。 但是,如果我想存儲除ElementC或ElementB或ElementA以外的任何內容,我會感到困惑。 我聲明這樣的列表如下:
List<? extends ElementC> list = new ArrayList<>();
而且我根本無法使用它,因為它只能存儲空值。 當我將List聲明為(注意,我正在使用位於“家庭中間”的類)時,會發生相同的事情:
List<? extends ElementB>
為什么這樣?
問題在於?
在運行時未知。 您必須替換具體的類/接口才能執行所需的操作。
如果您這樣做:
List<ElementA> list = new ArrayList<ElementA>();
您很好,因為ElementB
是 ElementA
。 同樣代表ElementC
。
List<? extends ElementA>
如果您在類中聲明它,並且在子類中可以將一些具體的東西替換為type參數,則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);
}
}
List<ElementA>
接受ElementA
, ElementB
和Element C
實例。
List<ElementB>
接受ElementB
和Element C
實例。
List<ElementC>
接受ElementC
實例。
您的示例中沒有理由使用通配符。
List<? super ElementA>
List<? super ElementA>
表示某種類型的List,它是ElementA
或超類。
List<? extends ElementB>
List<? extends ElementB>
表示某種類型的List,它是ElementB
的子類。 如果得到一個元素,它將是ElementB
或子類,但是它不知道該類是什么,因此不能確定添加的元素的類型正確,因為它是未知的(盡管它確實知道它是ElementB
的子類)。
通配符有一些用途,但您的示例不是其中之一。
您創建一個這樣的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
編譯器這樣做是為了使以前的情況永遠不會發生。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.