2021 03 20 泛型與逆變 協變 不變筆記

2021-10-22 16:39:11 字數 2631 閱讀 5733

目錄

泛型與逆變、協變、不變

1. 陣列是協變的

2. 未使用萬用字元的泛型類是不變的(為何泛型類無法強轉)

3. 使用萬用字元的泛型類可逆變可協變(泛型類強轉解決方案)

假設有parent、son、grandson三個類

class parent{}

class son extends parent{}

class grandson extends son{}

由於son可以向上轉型為parent , 所以son 可以向上轉型成parent ,形如這種a>b,則f(a) > f(b),就叫協變,我們都變了,但是關係不會變

會發現編譯器並不會報錯

由於 parent parent = (parent)new son();

所以 parent arr = (parent) new son[5];

雖然一旦執行起來,arr[2] = new parent() 會丟擲arraystoreexception異常

但以下三個在編譯期間均不會報錯

arr[0] = new grandson();

arr[1] = new son();

arr[2] = new parent();

由於son可以向上轉型為parent,但是listparents = (list)new arraylist直接編譯期報錯,同時listsons = (list)new arraylist同樣直接編譯期報錯,這種a>b,但f(a)和f(b)之間完全沒有任何關係,就叫不變

parent obj = (parent)new son();

但以下兩個編譯期直接報錯

listparents = (list)new arraylist();

listsons = (list)new arraylist();

所以泛型類無法強轉

由於son可以向上轉型為parent,且 list extends parent> list = (list extends parent>)new arraylist()  ,符合a>b,則f(a) > f(b),所以萬用字元泛型可以是協變的。

但是所有add操作都會報錯,因為? extends parent表示泛型可以是parent的任何子類,乙個父類可以有無限個子類,所以list無法確定究竟該接收哪個,所以選擇全報錯。

parent obj = (parent)new son();

發現這樣寫並不報錯

list extends parent> list = (list extends parent>)new arraylist();

但是所有新增行為都報錯

list.add(new son());

list.add(new grandson());

list.add(new parent());

list> list = new arraylist<>();

同樣所有新增行為都報錯

list.add(new son());

list.add(new grandson());

list.add(new parent());

由於son可以向上轉型為parent,且list super son> superlist = (list super son>)new arraylist(),符合a>b,則f(b) > f(a),所以萬用字元泛型可以是逆變的。只要add(son以及son的子類)就不會報錯,因為乙個類只有有限的父類,可以清晰的知道可以傳入哪些子類,所以不會報錯。

list super son> superlist =(list super son>) new arraylist();

superlist.add(new parent()); // 編譯報錯

superlist.add(new son()); // 不報錯

superlist.add(new grandson()); // 不報錯

所以

1. 如果想要強轉,需要通過萬用字元

2. 如果強轉的過程中,需要對傳入泛型物件進行修改,需要遵循psce原則(有類似add、set等操作,需要使用list super son>;有類似於get的操作,使用list)

public static void main(string args) 

private static listforcecast(list> list)

psce原則:

1. 生產者,即set或add,需要用super

2. 消費者,即get,需要用extend

3. 該方法表明,從son或son子類列表中取,加到parent列表中

private static void transfer(list super son> dest, list extend son> from)

泛型協變和逆變3

原文 01.協變性指的是 泛型型別引數可以從乙個派生類隱式轉化為基類 子類可以隱式的轉換為父類 例如string 可以轉化為object 在c 4.0中引入out關鍵字來標記泛型引數支援協變性 list.addrange ienumerable 方法 將其元素新增到 list的末尾的集合。集合自身不...

C 泛型的協變和逆變

可變性是以一種型別安全的方式,將乙個物件當做另乙個物件來使用。如果不能將乙個型別替換為另乙個型別,那麼這個型別就稱之為 不變數。協變和逆變是兩個相互對立的概念 在c 4.0之前,所有的泛型型別都是不變數 即不支援將乙個泛型型別替換為另乙個泛型型別,即使它們之間擁有繼承關係,簡而言之,在c 4.0之前...

協變與逆變

目錄 1.協變 2.逆變 在泛型之前,我們都知道可以將乙個派生類物件賦值給基類變數,這叫做賦值相容性。看下面這個例子 相容性示意圖如上。但是當我們新增泛型機制時 class animal class dog animal delegate t factory class program static...