Java 泛型 super T 中 super 怎麼 理解?與 extends 有何不同?

時間 2021-05-06 09:30:58

1樓:cjwddxm

簡單來說,<? extends T>、<? super T>這兩種方式主要是用來泛型賦值的時候用的,<?

extend T>就可以被泛型型別是T或T的子類的物件賦值,<? super T>可以被泛型型別是T或T的父類的物件賦值。除了賦值,其他場景都沒必要用。

至於兩種方式使用的區別,簡單理解的核心點就是子類可以自動(非強制轉換)轉為父類而父類不能自動轉為子類:

泛型存在的意義就是確定型別,<? extends T>、<? super T>也只是描述的元素和確定型別T的關係。

所以在新增元素的時候,<? extends T>存的都是T或T的子類,無法確定具體的型別。而<?

super T>存的是T或T的父類,所以只要你存的是T或T的子類,就都可以自動轉為T(其實也就是確定的型別)來新增。

而獲取元素的時候,需要乙個確定的型別來接收,所以對於<? extends T>來說,存的本來就是各種子類,就都自動轉為T。而對於<?

super T>來說,存的是T或T的父類,所以既無法用子類來接收(父類無法自動轉),也無法用父類來接收(無法確定型別),只能用所有類的基類Object來接收。

更簡單的理解方式:

新增元素的時候,要看T能否強轉為需要新增的元素。獲取元素的時候,要看要獲取的元素能否強轉為T。

這樣就能得出結論:

<? extends T>存的是T的子類,所以可以獲取但不能新增。

<? super T>存的是T的父類,所以可以新增不能獲取。

2樓:Devin老師

在最高票的邏輯下,補充一下。

這是兩種箱子的問題。

<? extend Fruit> 和 <? super Fruit> 是兩種箱子。

第二種箱子,Food<? super Fruit> foodBox, 這種食物箱子可以裝水果等食物,已經裝好了一些食物。現在來了乙個人,從這個箱子裡面拿(get)了一件食物出來,我們無法確定這個食物一定是水果,但如果這個人想往裡面(set)葡萄,是允許的,因為葡萄屬於水果,當然也屬於食物了。

所以,可寫不可讀。

3樓:Gradle

class

Person

}class

Student

extends

Person

}ArrayList

>x=newArrayList

>();x.

add(

newStudent

("001"

));ArrayList

<?

extends

Person

>s1=

x;sop(s1.

get(0).

name

);//可行泛型上限將泛型類中泛型成員轉為上限超類儲存

//s1.add(new Student("002"));//報錯設定泛型上限後無法新增/修改元素,原因:子類分支間不相容

ArrayList

<?

super

Student

>y=newArrayList

>();

//sop(y.get(0).name);//報錯泛型下限將泛型類中泛型成員轉為Object儲存y.

add(

newStudent

("002"

));//可行設定泛型下限後可新增/修改元素,原因:超類間相容

Studentm=(

Student)(y

.get(0

));sop(m

.name

);泛型限定的操作安全問題的原因:

①設定泛型上限後無法新增/修改元素,原因:子類分支間不相容(無共同下限型別),若加入新元素排序時(Set/Map)存在新元素無已存元素的成員屬性導致無法比較的問題

②設定泛型下限後可新增/修改下限型別元素,原因:超類間相容(存在共同下限型別),加入的新元素(被限定為共同下限型別)都包含已存元素的成員屬性,新元素排序時(Set/Map)不存在已存元素比較方法由於新元素無指定成員屬性導致無法比較的問題

4樓:李澤

extends:可讀不可寫

super :可寫不可讀

都沒有 :沒有繼承很開心,一遇繼承就完蛋

public class TestExtendsAndSuper {

static class Container implements Comparable>T tpublic Container(T tthis.t = tpublic T getreturn tpublic void set(T tthis.t = tOverride

public int compareTo(@NonNull Container oreturn 0; // not implementTest

public void testNoExtendsAndSuperContainer c1 = new Container<>(1Container c2 = new Container<>(1c1.set(2c1.getc1.

compareTo(c2Test

public void testNoExtendsAndSuper2Container c1 = new Container(1Container c2 = new Container(2c1.compareTo(c2); //compile errorContainer is not Number 儘管 Integer is NumberTest

public void testExtends1Container<? extends Number> c = new Container(1Container is Container<? extends Number>Test

public void testExtends2_couldGetContainer<? extends Number> c1 = new Container(1Number i = c1.getTest

public void testExtends3_couldNotSetContainer<? extends Number> c1 = new Container(1c1.set((Number) 1); //compile error!

why因為 Container<? extends Number>實際引用的物件可能是 Container也有可能是 Container, Container,Container等如果允許set,就會導致容器內型別錯誤,如下c1.set((Number)1.

2如果可行,豈不是在Container中設定了doubleTest

public void testSuper1Container<? super Integer> c1 = new Container(1Container is Container<? super Integer>Container<?

super Integer> c2 = new Container((Object) "hello"Test

public void testSuper2_couldSetContainer<? super Integer> c1 = new Container(1c1.set(1); // could set Integer and subclass of Integerc1.

set((Number)1); //compile errorpublic void testSuper3_couldNotGetContainer<? super Integer> c2 = new Container((Object) "hello"Integer i = c2.get(); compile error!

以為我們不知道實際的型別當然,可以用Object接

Object o = c2.get

5樓:姨夫的微笑

super...向上限定,泛型可以是E及其父類。參考map集合構造傳入乙個comparator比較器,父類map重寫了比較器方法的話,子類可以直接使用,不需要再定義乙個比較器。

extends...向下限定,可以是E及其子類。見於集合addAll方法傳的引數,把a集合新增到b個集合的時候,a裡面的元素必須是b或者b的子類。

6樓:袁太富

List :」存的時候只能選乙個型別。「

List <? extends Fruit> 意思: List中所有元素都是Fruit的子類(包含本身),

List <? super Fruit> 意思: List中所有元素都是Fruit的父類(包含本身)

1、List <? extends Fruit>

假設:Fruit有子類A、B、C 那麼 list.add(A);list.add(B);list.add(C);顯然錯誤(不能存多個類)。

雖然我們現在看的是ABC3個類就會問為什麼會把不同型別的存進去,我這樣存不就好了。list.add(A);list.

add(A);其實這也是錯誤的,因為在執行之前他可不知道你到底add進去的東西是什麼型別,是一樣還是不一樣,因例項化的時候是 ? 待定。為了避免型別不同的情況,所以會編譯不通過。

2、List <? super Fruit>

假設:Fruit有子類A、B、C 那麼 list.add(A);list.add(B);list.add(C); 這卻是可以的,為什麼呢:

因為他是這麼存的:list.add((Fruit)A);list.add((Fruit)B); 自動強轉了。因為小轉大是隱性的,大轉小才是強轉需要加型別。

那這裡為什麼又不能存Fruit的父類呢? 因為見假設1,它是?號,型別代表待定,不跑起來他也不知道你到底存的什麼。

所以我們能手動add()進去的資料都必須是絕對安全的(最低階父類:本身)才能通過。所以直接add父類也是不行的。

2016-06-22

2018-03-26 更

public

static

void

main

(String

args

)throws

IOException

,ClassNotFoundException

class

Food

class

Fruit

extends

Food

class

extends

Fruit

public

static

ArrayList

>getFoods

()public

static

ArrayList

>getFruits()

如何正確理解java中的泛型型別推導?

一一哥 泛型是將資料型別引數化。將資料型別作為引數傳遞 語法 資料型別 1.1 泛型集合 將資料型別作為集合的引數,集合中每個元素必須都是這個泛型的資料型別。1.1.1 泛型集合優點 減少頻繁的裝箱和拆箱,以及資料型別的判斷 1.1.2 泛型集合的特點 乙個集合只存一種型別的資料。1.1.3 語法 ...

java中的io 流到底怎麼理解?

王boy 對於IO的理解,流這個概念十分重要。舉個簡單的例子,你用壺往杯子裡倒水,壺裡的水不可能一下子就跑到被子裡,而是需要乙個過程。這個過程更像是連續的過程,源源不斷進行著。回到計算機上來,舉乙個計算機硬碟和記憶體的例子,硬碟需要傳1g的資料到記憶體中以便處理,但是由於傳輸頻寬等方面的限制,1g資...

java中的輸入輸出流該怎麼理解?

Bosco 檔案輸入輸出主要重點知道二進位製碼亂碼的中間橋梁 inputstreamreader 了解了這個往上推斷就明白脈絡 buffered只要是對於檔案在堆中能更有效率。 趙北雲 你是困惑裝飾器模式還是困惑輸入 輸出的本質呢?基於原本的實現增加新的行為就是裝飾器模式的目的了比如想減少IO次數可...