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的協程