簡體   English   中英

Java中的泛型類型-高級多態

[英]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>接受ElementAElementBElement C實例。

List<ElementB>接受ElementBElement 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM