Kotlin學習筆記(七)-泛型
- 2019 年 12 月 19 日
- 筆記
前言
這節我們說下Kotlin的泛型。首先默認大家對Java泛型有個基本的認識,如果 不熟悉Java的泛型,可以閱讀文章,或是看下Java《Java核心技術卷一基礎知識第10版》中關於泛型章節的知識,講述的也很詳細。其實Kotlin的泛型和Java很相似。他們都是偽泛型,所謂偽泛型就是我們們是無法獲取到泛型的具體的類型的。以為Java存在類型擦除和轉換。本篇還是和反射一樣,從實際程式碼編寫角度,說下Kotlin的泛型
逆變與協變
泛型的逆變與協變其其在Java中也有。簡單概括來說就是<? extends T>實現了泛型的協變,<? super T>實現了泛型的逆變。具體的這兩種有什麼特性可以看開頭兩篇文章。
Kotlin中的協變與逆變
- 泛型參數即可作為傳入的參數,也可以作為返回值,但被in和out關鍵字修飾後就不一樣了
- out 叫協變 只能作為返回值讀取 不能寫入和修改(Kotlin的list中只有get方法 沒有add)
- in 叫逆變 只能寫入不能讀取 只能作為參數傳入 (Kotlin中的Comparable只能傳入參數)
- 不變 既沒有in也沒有out就叫做不變 如MutableList(相當於java中的list)
- 協變點:返回值類型是泛型類型參數
- 逆變點:入參類型是泛型參數的類型
- @UnsafeVariance 型變點偽例(當時協變的時候 泛型作為參數入參會報錯 那麼如果我們想忽略這個錯誤那麼我就可以用這個註解標識)
程式碼示例:
協變 :泛型類型與實參的類型的繼承關係相同
val listOf: List<Number> = listOf<Int>(1, 2, 3)
在泛型參數前面加上out表示協變,作為返回值,為只讀類型, 它的子類的泛型參數的類型是父類的泛型參數類型的子類,也就是說泛型參數的繼承關係與類的繼承關係保持一致(所以叫協變),比如Number是Int的父類 那麼List<Number>也是List<Int>父類型;
逆變 泛型參數的繼承關係與類的繼承關係相反
val value: Comparable<Int> = object : Comparable<Any> { override fun compareTo(other: Any): Int { return 0 } }
在泛型參數前面加上in表示逆變,作為傳入的參數,為只寫類型,它的泛型參數的繼承關係與類的繼承關係相反,比如父類是Any,子類是Int。
不變 類型必須保持一致 泛型之間沒有關係
val mutableList: MutableList<Int> = mutableListOf<Int>(1, 2, 3)
星投影 其本質就是類似Java中通配符 ?
val listOf1: List<Number> = listOf(1, 2, 3) //這是可以的 val listOf2: List<*> = listOf(1, 2, 3) // val listOf3: List<Number> = listOf<*>(1, 2, 3)//ERROR //這是可以的 val value1: Comparable<*> = object : Comparable<Any> { override fun compareTo(other: Any): Int { return 0 } } //可以 val value2: Comparable<*> = object : Comparable<Int> { override fun compareTo(other: Int): Int { return 0 } } //不可以 // val value3: Comparable<Int> = object : Comparable<*> {//error // override fun compareTo(other: Int): Int { // return 0 // } // } // val hello=Hello<*>//ERROR 因為泛型實參時不能用*代替 //java 是可以有弱類型的(目的是兼容1.5) Kotlin不可以 定義了泛型了 創建的時候就必須指定泛型
星投影只能只能作為形參,不能作為實參。
reified 關鍵字
reified單詞含義為具體化的。用法
inline fun <reified T> testGenerics2() { println(T::class.java) }
加上reified關鍵字就可以列印出來他的類型了,這是在Java中做不到的。
inline關鍵字的作用
inline表示內聯函數
- inline 修飾符影響函數本身和傳給它的 lambda 表達式:所有這些都將內聯到調用處。
- 內聯可能導致生成的程式碼增加;不過如果我們使用得當(即避免內聯過大函數),性能上會有所提升,尤其是在循環中的「超多態(megamorphic)」調用處。
- inline關鍵字的作用是 一個方法帶參數 同時這個方法中的參數是一個高階函數(也就是Lambda表達式),那麼inline可以提升性能
結語
其實泛型很難講清楚。就算講清楚了,也可能晦澀難懂。其實泛型掌握了編寫規則。多實踐,就好了。下篇講下Kotlin的協程