簡體   English   中英

<?超級E>和<?擴展E> for List

[英]<? super E> and <? extends E> for List

具有以下簡單的類結構:

class A {
}

class B extends A {
}

class C extends B {
}

我正在創建一個ArrayList來保存先前創建的類的對象:

List<? extends A> list1 = new ArrayList<A>();
List<? extends B> list2 = new ArrayList<B>();
List<? extends C> list3 = new ArrayList<C>();

List<? super A> list4 = new ArrayList<A>();
List<? super B> list5 = new ArrayList<B>();
List<? super C> list6 = new ArrayList<C>();

對於每個列表,我正在嘗試添加每個先前創建的類的1個對象:A,B,C。 唯一可能的組合是:

  • 將類A,B,C的對象添加到list4

  • 將類B和C的對象添加到list5

  • 將類C的對象添加到列表list6。 其余的嘗試給出了編譯器錯誤,例如:

類型List中的方法add(capture#1-of?extends A)不適用於參數(A)

為什么我不能將類A,B,C的任何對象添加到list1 / 2/3? 為什么例如list4接受類A,B,C的對象,如果它們應該是A類的超類,因為list4是定義的?

“?extends A”表示“某種類型派生自A(或A本身)”。 例如, List<ByteArrayOutputStream>List<? extends OutputStream>兼容 List<? extends OutputStream> - 但是您不能將FileOutputStream添加到這樣的列表中 - 它應該是List<ByteArrayOutputStream> 你所知道的是, 列表中獲取的任何內容都將是某種類型的OutputStream

“?super A”表示“某種類型,它是A(或A本身)的超類”。 例如, List<OutputStream>List<? super ByteArrayOutputStream>兼容 List<? super ByteArrayOutputStream> 你絕對可以將ByteArrayOutputStream添加到這樣的列表中 - 但是如果你從列表中獲取一個項目,你就無法真正保證它。

有關更多信息,請參閱Angelika Langer的Generics FAQ

類型定義List<? extends A> List<? extends A>不可用於可變列表 - Java泛型Java Generics Pdf中給出的解釋是

add()方法接受類型為E的參數,即集合的元素類型。 當實際類型參數為?時,它代表某種未知類型。 我們傳遞給add的任何參數都必須是這種未知類型的子類型。 既然我們不知道那是什么類型,我們就無法傳遞任何東西。

但是,當typedef是List<? super A> List<? super A>那么類型參數? 是隱式輸入的。

List<? extends A> list1 

它是一個列表,其type元素可以是A的任何未知子類。例如,它可以是D子類。 因此,你不能添加任何東西,它可能是錯的......

List<? super A> list4

它是一個列表,其類型元素可以是A,或者是A的超類(在這種情況下不存在,除了Object)。 因此,您可以向其添加A對象,或者添加A的任何子類,例如B或C.

它不起作用。

你應該使用<? extends T> 在創建函數時<? extends T>哪個參數是某種類型的未知子類型的集合,並且您想要從該集合中獲取對象:

int sum(Collection<? extends Integer> collection) {
    for (Integer : collection) {
        // do sth
    }
    // ...
}

您無法向此集合添加新項目,因為您不知道此集合包含哪種具體類型。 你所知道的是那種類型擴展了Integer

你用<? super T> <? super T>當你想要將T類型的新項目添加到集合並返回該集合時,但是你不能保證你可以從它中檢索什么,你必須轉換get()結果或檢查它的類型。 您可以安全地添加類型的項目, T和亞型,並檢索類型的項目T

List<? super B> List<? super B>允許您使用B的超類型任何的解釋,即list5 =新的ArrayList <A>(); 或list5 = new ArrayList < Object >();

您可以安全地將B(和子類型)添加到使用B的超類型的每個列表,但是您不能添加任何超類型的B.想象一下:

public void myAdd(List<? super B> lst) {
  lst.add(new Object()) //this is a supertype of B (compile time error)
}
...
ArrayList<A> list = new ArrayList<A>();
myAdd(list); //tries to add Object to a list of type A

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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