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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

kotlin语言中的out和in

發布時間:2024/1/18 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 kotlin语言中的out和in 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在 kotlin 語言中,out 表示協變,in 表示逆變;協變和逆變并不是 kotlin 獨有的概念,像 Java、C#都有這樣的概念;為了能夠理解 kotlin 語言中的 out 和 in,我們先用 Java 的泛型來舉例,我們需要用泛型,是因為它的好處就是在編譯的時候能夠檢查類型安全,并且所有的強制轉換都是自動和隱式的。

1、Java 中的 ? extends T 和 ? super T

1、1 ? extends T

ps:代碼是在 AndroidStudio 工具上寫的

建立一個 Java 文件鳥類 Birds;

public class Birds { private String name; public Birds(String name) { this.name = name; } public void flight() { System.out.println("我是" + name + ",屬于鳥類,我能飛行"); } }

建立一個 Java 文件烏鴉類 Crow 并繼承 Birds;

public class Crow extends Birds { public Crow(String name) { super(name); } }

新建一個 Java 文件的泛型類 TestBirds 并限制泛型 T 是 Birds 的子類;

public class TestBirds<T extends Birds> { public void actionBirds(List<T> birds) { for (T bird : birds) { bird.flight(); } } }

在程序入口嘗試使用 List<Crow> list 作為參數傳遞給 TestBirds 的 actionBirds 方法;

List<Crow> list = new ArrayList<>(); TestBirds<Birds> testBirds = new TestBirds<>(); Crow crow = new Crow("烏鴉"); list.add(crow); /** * 這里 list 地方會編譯報紅線 */ testBirds.actionBirds(list);

這時候傳入 list 發現編譯不通過,我們這里分析一下:TestBirds 是泛型類,沒有使用的之前,T 是不確定的,使用之后 T 是確定的,它是 Birds;把 list 作為參數傳入 actionBirds 方法中,等同于 List<Birds> birds = list,但是 List<Birds> birds = list 是不成立的,雖然 Crow 繼承于 Birds,birds 只保存的是 Birds 類型的對象,list 只保存 Crow 類型的對象,birds 和 list 是沒有任何關系的。

TestBirds 類中新添加一個 actionBirds2 方法,該方法是在 actionBirds 方法的基礎上修改的;

public void actionBirds2(List<? extends T> birds) { for (T bird : birds) { bird.flight(); } }

在程序入口使用 List<Crow> list 作為參數傳遞給 TestBirds 的 actionBirds2 方法;

List<Crow> list = new ArrayList<>(); TestBirds<Birds> testBirds = new TestBirds<>(); Crow crow = new Crow("烏鴉"); list.add(crow); /** * 這里 list 地方會編譯報紅線 */ // testBirds.actionBirds(list); testBirds.actionBirds2(list);

這時候發現 testBirds.actionBirds2(list) 這行代碼編譯通過了,是不是感覺很神奇?這里分析一下:把 list 作為參數傳入 actionBirds2 方法相等于 List<? extends Birds> birds = list,它是成立的,List<? extends Birds> birds ,表示集合存儲的是 Birds 和 Birds 的子類對象,限定了上屆,而 list 存儲的是 Birds 子類的對象,所以代碼編譯通過,它是成立的;上界通配符 < ? extends T>,用 extends 關鍵字聲明,表示參數可能是T,或者是T的子類。

1、2 ? super T

在上面原有代碼的基礎上,在 TestBirds 類中添加一個 actionBirds3 方法;

public void actionBirds3(List<T> birds,List<T> crows) { for (T crow : crows) { birds.add(crow); } }

在程序入口嘗試調用 TestBirds 的 actionBirds3 方法;

List<Crow> list = new ArrayList<>(); TestBirds<Crow> testBirds = new TestBirds<>(); Crow crow = new Crow("烏鴉"); list.add(crow); List<Birds> birdsList = new ArrayList<>(); testBirds.actionBirds3(birdsList,list);

到這里后,發現 actionBirds3 方法的第一個參數就報紅色編譯錯誤了,原因是實例化 TestBirds 類對象的時候,T 被 Crow 替換了,birdsList 只存儲 Birds 類型的數據,而 actionBirds3 方法的第一個參數只存儲 Crow 類型的數據,所以2者沒有任何關系,所以語法編譯錯誤。

我們在 TestBirds 中新添加一個 actionBirds4 方法,在 actionBirds3 的基礎上改動一下第一個參數;

public void actionBirds4(List<? super T> birds,List<T> crows) { for (T crow : crows) { birds.add(crow); } }

在實參不變的情況下,在程序入口調用 TestBirds 的 actionBirds4 方法;

List<Crow> list = new ArrayList<>(); TestBirds<Crow> testBirds = new TestBirds<>(); Crow crow = new Crow("烏鴉"); list.add(crow); List<Birds> birdsList = new ArrayList<>(); /** * 這里 birds 地方會編譯報紅線 */ // testBirds.actionBirds3(birds,list); testBirds.actionBirds4(birdsList,list);

這時候發現調用 TestBirds 中的 actionBirds4 方法編譯通過,分析一下:actionBirds4 方法的第一個參數為 List<? super T> birds,? super T 是下限通配符,它表示在使用中限定參數類型為 T 或者是 T 的父類,birds 存儲的是 T 類型和 T 父類的對象;在實例化 TestBirds 的過程中,把 Crow 替換成了 T,Birds 剛好是 Crow 的父類,調用 TestBirds 的 actionBirds4 方法傳遞第一個參數時相當于 List<? super Crow> birds = list,所以編譯通過。

2、kotlin 中的 out 和 in

2、1 out

在上面 ? extends T 的代碼案例中,TestBirds 類中的 actionBirds2 方法的第一個參數 birds 集合加了 ? extends T 進行限制,然后用 for 循環遍歷 T 的元素進行取出來,這樣的操作是讀取;? extends T 限定了通配符類型的上界,所以我們可以安全地從其中讀取卻不可以修改數據;我們可以把那些只能從中讀取的對象稱為生產者;List<? extends T> 這樣的類型不進行消費的生產者,以保證類型運行的安全,這就是協變;在 kotlin 中用 out 表示,kotlin 中的 “out T” 等同于 Java 的 “?extends T”;下面用 kotlin 的 out 關鍵字舉個例子:

新建一個 kotlin 類 TestBirds2 并寫一個和 TestBirds 類 actionBirds2 效果一樣的函數;

class TestBirds2<T: Birds> { fun actionBirds2(birds: MutableList<out T>) { for (bird: T in birds) { bird.flight() } } }

在程序入口調用 TestBirds2 中的 actionBirds2 函數;

var testBirds2: TestBirds2<Birds> = TestBirds2<Birds>() var crow: Crow = Crow("烏鴉") var crowList: MutableList<Crow> = mutableListOf(crow) testBirds2.actionBirds2(crowList)

2、2 in

在上面 ? super T 的代碼案例中,TestBirds 類中的 actionBirds4 方法的第一個參數 birds 集合加了 ? super T 進行限制,然后用 for 循環遍歷第二個參數crows 的 T 元素進行取出來,再將 T 元素放入到 birds 集合中;? super T 限定了通配符類型的下界,所以我們可以安全地從其中修改數據,也就是將 T 元素放入到 birds 集合中;我們可以把那些只能從中修改的對象稱為消費者;List<? super T> 這樣的類型獲取出來的數據類型是 Object,沒有意義,可認為不進行生產的消費者,以保證類型運行的安全,這就是逆變;在 kotlin 中用 in 表示,kotlin 中的 “in T” 等同于 Java 的 “?super T”;下面用 kotlin 的 in 關鍵字舉個例子:

在 TestBirds2 類中寫一個和 TestBirds 類中 actionBirds4 方法效果一樣的函數;

fun actionBirds4(birds: MutableList<in T>,crow: MutableList<T>) { for (t: T in crow) { birds.add(t) } }

在程序入口調用 TestBirds2 中的 actionBirds4函數;

var testBirds2: TestBirds2<Crow> = TestBirds2<Crow>() var crow: Crow = Crow("烏鴉") var crowList: MutableList<Crow> = mutableListOf(crow) var birdsList: MutableList<Birds> = mutableListOf() testBirds2.actionBirds4(birdsList,crowList)

2、3 類型投影

上面的 out 和 in 的例子使用起來還是有限制,因為有 T 繼承于 Birds 的局限;這里講一下類型投影,在講類型投影之前先說一下 Any,Any 是 kotlin 語言的祖宗類,類似于 Java 中的 Object,但是又不是等于 Object,因為 Any 只有 equals、hashCode 和 toString 這3個函數;將一個類聲明為泛型類,泛型類型可以出現在 out 位置,也可以出現在 in 位置,我們就可以在使用處將其聲明成協變或者逆變,就等于把這個類型投影出某一面進行使用,就屬于類型投影;就拿泛型類 MutableList<T> 來說,真正要實例化 MutableList 的時候,T 的位置可以多添加 in 或者 out, 把這個類型投影出某一面進行使用,也就是 MutableList 的讀取數據方法 get 或者寫入數據方法 add;下面就拿 MutableList 寫代碼舉例一下:

var mutableList: MutableList<out Any> = mutableListOf("公眾號小二玩編程",2,3,4,5) var size: Int = mutableList.size - 1 var any: Any? = null for (i: Int in 0 .. size) { any = mutableList.get(i) println("第" + (i + 1) + "any是--" + any) } var mutableList2: MutableList<in String> = mutableListOf() mutableList2.add("公眾號小二玩編程") /** * 這里 Int 類型,編譯會報錯,因為 mutableList2 做了 in String 限制 */ mutableList2.add(2)

本篇文章寫到這里就結束了,由于技術水平有限,文章中難免會有錯誤,歡迎大家批評指正。

總結

以上是生活随笔為你收集整理的kotlin语言中的out和in的全部內容,希望文章能夠幫你解決所遇到的問題。

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