中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

kotlin中的高級特性--協變與逆變(反變)

發布時間:2020-08-05 15:20:08 來源:網絡 閱讀:4498 作者:洛基loky 欄目:開發技術
逆變性與協變性是kotlin中相對于java的新特性,這個成為不少java轉kotlin學習的一個坎,在這篇文章里我將詳細介紹和推導逆變性與協變性的由來。

內容參考了以下兩篇博客:
http://www.cnblogs.com/lemontea/archive/2013/02/17/2915065.html
http://www.cnblogs.com/Ninputer/archive/2008/11/22/generic_covariant.html

在此之前我們需要明白一個大前提:
java不允許向下轉型(父類轉換成子類)
定義

假設有這樣兩個類型:TSub是TParent的子類,顯然TSub型引用是可以安全轉換為TParent型引用的。如果一個泛型接口IFoo<T>,IFoo<TSub>可以轉換為IFoo<TParent>的話,我們稱這個過程為協變,而且說這個泛型接口支持對T的協變。而如果一個泛型接口IBar<T>,IBar<TParent>可以轉換為T<TSub>的話,我們稱這個過程為反變(contravariant),而且說這個接口支持對T的反變。因此很好理解,如果一個可變性和子類到父類轉換的方向一樣,就稱作協變;而如果和子類到父類的轉換方向相反,就叫反變性。

我們來具體看一下體現到kotlin語法中是什么樣的

kotlin中有out和in關鍵字來表示協變和逆變,我們通過out的兩個來認識什么是逆變:
1. 泛型只能在返回值中出現
2. 只能進行子類向父類的轉型

eg:
//有如下兩個類
//1.不支持逆變與協變
MyFuncA<T>
//2.支持協變
MyFuncB<out T>
//現對其進行初始化然后轉型
MyFuncA<object> funcAObject = null;
MyFuncA<string> funcAString = null;
MyFuncB<object> funcBObject = null;
MyFuncB<string> funcBString = null; 
funcAObject = funcAString;//編譯失敗,MyFuncA不支持逆變與協變
funcBObject = funcBString;//變了,協變
funcBObject = funcBInt;//編譯失敗,值類型不參與協變或逆變

代碼中可以看出使用了協變的泛型對象MyFuncB<out T>可以進行子類向父類的轉換,而不支持逆變和協變得MyFuncA<T>則不允許向上或者是向下的轉換。

其實以上的兩條含義只是一條,只不過在不同的場景下表現不一樣而已,我們一起來看一下:

假設有這樣一個方法:

String Base<out T>
{
  void Test(T t)
}

泛型協變的,但我們允許有方法可以在參數中使用泛型(實際上這樣是不行的,這里我們通過反正法證明來證明這一結論

Base<object> BaseObject = null;
Base<string> BaseString = null;
BaseObject = BaseString;
BaseObject.Test("");

我們來看一下函數的調用過程:

kotlin中的高級特性--協變與逆變(反變)

BaseObjectBaseString初始化,所以
BaseObject.Test("")的調用實質上是調用BaseString.Test(""),而BaseString中要的泛型Tstring,而實際BaseObject給出的泛型Tobject
object無法向下轉型為string,因此出現類型轉換的異常。

由此我們得出以上結論,因為泛型是協變的,進行子類向父類的轉型,所以泛型不能在傳入參數中使用,只能在返回值中使用。

逆變性反之也是一樣的推導,由于進行的是父類向子類的轉型,在返回值返回的時候要求的是子類的泛型,但實際上是調用父類的方法返回了父類,同樣出現了向下轉型的錯誤,因此逆變性中泛型只能在傳入參數中使用,不能在返回值中使用。

eg:

//過程同上
T Base<in T>.Test()

泛型逆變的,但我們允許有方法可以在返回值中使用泛型(實際上這樣是不行的,這里我們同樣通過反正法證明來證明這一結論)

Base<object> BaseObject = null;
Base<string> BaseString = null;
BaseString = BaseObject ;
BaseString.Test();

只要按照協變時的調用方法看代碼的調用就會發現我們在返回值的時候得到的是object,而我們要的是string,同樣出現向下轉型的錯誤。

逆變和協變是保證運行時安全而出現的機制,編碼時編譯器已經強制我們在逆變中不能在函數返回值中使用泛型,在協變中不能在函數參數中使用泛型,以保證運行時的安全,也就是將我們可能產生的類型轉換異常在編譯階段給解決了!
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

凭祥市| 彝良县| 瓦房店市| 玛纳斯县| 凌海市| 镇平县| 濮阳市| 和政县| 金平| 任丘市| 牡丹江市| 华安县| 青阳县| 海安县| 襄汾县| 双柏县| 望谟县| 华安县| 崇州市| 磐安县| 衡南县| 嘉鱼县| 潼关县| 南开区| 五原县| 微博| 廊坊市| 元氏县| 彰武县| 婺源县| 双鸭山市| 呼玛县| 银川市| 青神县| 西平县| 杭锦后旗| 鲜城| 徐闻县| 互助| 泸西县| 肇东市|