Kotlin學習(一)—Kotlin的泛型

前言

在Kotlin中使用泛型的方式跟Java大致相似,其中也有一些特性的差異。不管是Java中的泛型仍是Kotlin中的泛型,總有些概念會讓人產生困惑。接下來回結合Java的泛型來學習Kotlin的泛型。安全

Kotlin中泛型的使用

在泛型的使用中,最經常使用到的就是泛型函數以及泛型類。在介紹這兩種方式的使用以前,先介紹一下泛型的類型參數。app

泛型類型參數

泛型的類型參數就是在聲明泛型時定義的類型形參,代表了在使用泛型時定義的一種類型。在泛型實例化是類型形參就被替換成了類型實參。好比:List  實例化爲   List時,類型形參T就被替換成了類型實參String。函數

因爲泛型是在Java 1.5時引入Java的,爲了兼容老版本,在Java中容許使用沒有類型形參的泛型。好比:List list = new ArrayList();這種生命是容許存在的。可是在Kotlin中泛型聲明必須聲明類型形參或者可以推導出類型形參。好比:val list = listof("a", "b");類型形參被推倒爲String類型或者List直接聲明爲String類型。學習

泛型函數以及泛型類

//泛型函數
fun <T> someFunc(item: T): List<T> {
    // do something
}
複製代碼
//泛型類
class Hello<T> {
    val value: T
}
複製代碼

能夠看到,在kotlin中使用泛型函數跟泛型類的方式與Java大體相同。除此以外,Kotlin還支持爲一個類型制定多個約束的特性。ui

參數類型約束

在Kotlin中能夠爲類型參數指定約束,好比:fun  sum() T,這個泛型函數指定了類型參數的上限爲Number類型,那個類型參數只能是Number或者Number的子類。這個在Java中的表示是extends實現,即:spa

code

處了上面的約束外,Kotlin還能夠指定多個約束。接口

fun <T> someFunc(value: T) where T : CharSequence, T : Appendable {
	if (!value.endsWith('.')) {
		value.append('.')
	}
}
複製代碼

上面這個泛型函數就指定了多個類型參數約束,在上面的狀況下,類型參數必須實現CharSequence和Appendable兩個接口。get

類型參數的空與非空:在Kotlin中每一個類型都有空與非空兩種狀況,實現泛型時也是如此。好比:List<String?>聲明類型參數爲一個可空的String類型,而List聲明類型參數爲不可空的String類型。string

運行時的泛型

和Java同樣,在運行時Kotlin的類型信息也會被擦除,類型擦除隨之帶來的就是類型的消失。

類型擦除在Kotlin中的影響

  • 函數參數受到類型擦除的影響,好比:fun func1(list: List); fun func2(list: List);這兩個使用List泛型,受到類型擦除的影響,在運行時,沒法分辨兩個函數參數的差別;
  • 類型檢查,在類型擦書後,運行時沒法檢查對應的類型。好比 value is List,在Kotlin中的替代方式是value is List<*>,利用星號投影檢查。

實化類型參數

實化類型參數的意思就是可使用類型參數。這個特性是Kotlin中加入的,一般是在內聯函數

inline fun <reified T> isA(value: Any) = value is T
複製代碼

能夠看到在內聯函數中能夠直接使用類型參數T。這樣的代碼在普通函數中是不能正常編譯的(會爬出異常Error: Cannot check for instance of erased type: T)。能夠在內聯函數中使用是由於內聯函數直接以字節碼的形式插入到調用的地方,因此在運行時能夠獲取到類型實參。還有就是reified關鍵字的做用就是聲明瞭類型參數在運行時不被擦除。

Kotlin中的型變

不變型

Kotlin的不變型指的是:例如,對於兩種任意類型A和B,MutableList既不是MutableList的子類型也不是超類型,那麼成爲在該類型參數上是不變型的(Java中全部的類型都是不變型的)。

協變

在Kotlin中對於一個泛型類,若是A是B的子類型, SomeClass就是SomeClass的子類型,也就是說子類型被保留了,這樣就是協變。

//類被聲明成在T上協變
class SomeClass<out T> {
	fun someFinc(): T
}
複製代碼

上面的代碼中就是聲明協變的方式,即加入out關鍵字。協變只能生產類型T而不能消耗類型T,好比:只能get不能set,也就是協變是隻讀的。

在Java中與之對應的是<? extends T>的上界通配符。

逆變

在Kotlin中逆變能夠看作是協變的鏡像,下面是聲明逆變的方式。

//聲明逆變類型
interface Comparator<in T> {
	fun compare(e1: T, e2: T): Int {} //聲明逆變使用in關鍵字
}
複製代碼

逆變能夠寫入,可是返回只能是基礎類型。

在Java與之對應的是<? super T>下界通配符。

星號投影

而在 Kotlin 中,在參數類型未知時,能夠用星投影來安全的使用泛型。可是MutableList<*>與MutableList<Any?>是不同的。MutableList< * >至關於MutableList<out Any?>,是隻讀的。由於不明確具體類型的狀況下,讀是安全的,寫是不安全的。

在Java中與之對應的是<?>無界通配符。

總結

Kotlin中的泛型與Java是相同的,處了幾個Kotlin新加入的特性(好比:多約束類型,實化參數等),其餘都與Java相通。

以上內容並無講明更多的細節,只是列出了Kotlin中泛型的內容以及與Java泛型的聯繫。感興趣的同窗能夠繼續深刻學習。

相關文章
相關標籤/搜索