日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

这一次,终于弄懂了协变和逆变

發布時間:2023/12/4 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 这一次,终于弄懂了协变和逆变 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、前言

劉大胖決定向他的師傅燈籠法師請教什么是協變和逆變。

劉大胖:師傅,最近我在學習泛型接口的時候看到了協變和逆變,翻了很多資料,可還是不能完全弄懂。

燈籠法師:阿胖,你不要被這些概念弄混,編譯器可不知道你說的什么協變逆變。這個問題,首先你得弄懂什么叫類型的可變性。

劉大胖:可變性?

二、可變性

燈籠法師:對,可變性是以一種類型安全的方式,將一個對象作為另一對象來引用。雖然是可變,但其實對象的引用地址是不會變的,只是忽悠下編譯器。

劉大胖:師傅說的將一個對象作為另一對象來引用?這不就是繼承么?

燈籠法師:是的,你可以看下面代碼演示(C#):

劉大胖:哦,我理解了,由于MemoryStream繼承于Stream,所以MemoryStream的對象可以變為Stream的對象,原來我天天在接觸可變性,我竟然不知道。

燈籠法師:是的,這種轉變其實遵守了里氏替換原則,愛徒,你可還記得?

劉大胖:當然,為了面試早已爛熟于心。里氏替換原則(LSP):指的是所有引用基類的地方都可以使用其子類的對象。可是師傅,這個和協變逆變有什么關系呢?

三、協變

燈籠法師:協變和逆變只是可變性的分類,主要用于泛型接口和委托中。協變逆變只是類型轉換的方向不同。我們先看下接口協變吧,假如有Apple類繼承于Fruit,如下:

燈籠法師:然后現在寫了一個打印水果名稱的方法,如下:

燈籠法師:這時如果你打算打印一些蘋果的名稱,你會怎么寫?

劉大胖:這不是很簡單,Apple繼承自Fruit,那可以直接使用PrintFruit類了。擼了下,怎么報錯了?代碼如下:

燈籠法師:大胖,你要理清楚,雖然Apple繼承Fruit,但List<Apple>和List<Fruit>卻一點關系也沒有,如圖:

劉大胖:那如果這樣,豈不是要為每一種水果都要定義一個PrintFruit方法,我覺得官方不會不知道這個問題吧?

燈籠法師:這種問題,官方當然知道了,所以才有了泛型接口的協變用以支持List<Apple>自動轉為List<Fruit>。C#中使用out表示泛型參數的可協變性,List沒有out約束,所以不能協變,但它的基類IEnumable卻實現了,如圖:

燈籠法師:所以只要把PrintFruit的參數類型換成IEnumable就可以了,如圖:

劉大胖:那為什么List<T>不能加out以支持協變呢?

燈籠法師:愛徒問的好,List繼承于IEnumable,它比IEnumable更寬泛,它支持讀和寫,但協變只能可讀,主要用于約束輸出參數。

劉大胖:好吧,我回去再消化下。師傅你再講一下什么是逆變吧。

四、逆變

燈籠法師:逆變是相反的,即支持List<Fruit>轉為List<Apple>,泛型接口上添加in約束輸入參數。

劉大胖:有點懞,師傅你還是用代碼吧!

燈籠法師:好吧,假如現在我要讓蘋果列表或桔子列表可以按名稱排序,需要一個定義一個水果比較器,此比較器能用于任何種類的水果列表,代碼如下:

燈籠法師:現在給蘋果和桔子列表按名稱排序吧,代碼如下:

劉大胖:師傅你別忽悠我,Sort的參數可是要具體類型的比較器的,你看代碼:

燈籠法師:大胖,就這是逆變,以使得基類的泛型對象替代子類的泛型對象,主要是因為IComparer<T>中使用了in關鍵字來約束,代碼如下:

五、總結

劉大胖:哦,我有點明白了,協變就是支持泛型子類自動轉泛型父類,逆變就是支持泛型父類自動轉泛型子類。

燈籠法師:也可以這么理解,但這些轉換只是針對編譯器,其引用地址并沒有改變。

翻外篇1:

協變:String =>Object

逆變:Object => String

翻外篇2:

燈籠法師在劉大胖走后從背后拿出手機,屏幕上顯示來不及關閉的知乎APP:

把復雜的技術簡單的寫出來,更多文章請關注我的公眾號:

總結

以上是生活随笔為你收集整理的这一次,终于弄懂了协变和逆变的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。