泛型實體化
Java中的泛型是通過類型擦除機制來實作的,而Kotlin卻允許将内聯函數中的泛型進行實化。
要将某個泛型實化需要兩個前提條件。首先,該函數必須是内聯函數才行,也就是要用inline關鍵字來修飾該函數。其次,在聲明泛型的地方必須加上reified關鍵字來表示該泛型要進行實化。示例代碼如下:
inline fun <reified T> getGenericType() = T::class.java
然後我們就可以通過以下代碼獲得泛型的具體類型了:
fun main() {
val result1 = getGenericType<String>()
val result2 = getGenericType<Int>()
println("result1 is $result1")
println("result2 is $result2")
}
運作結果如下
泛型實體化的應用
泛型實體化的功能允許我們在泛型函數當中獲得泛型的實際類型,也就是的 a is T, T::class.java 這樣的文法成為了可能。
對于啟動一個Activity,以前我們使這樣寫的
val intent = Intent(context, TestActivity::class.java)
context.startActivity(intent)
但是Kotlin的泛型實體化讓我們有了更好的選擇
建立一個reified.kt
inline fun <reified T> startActivity(context: Context){
val intent = Intent(context, T::class.java)
context.startActivity(intent)
}
本來Intent接收的第二個參數應該是一個具體的Activity的Class類型,但由于T是一個被實體化的泛型,是以這裡我們直接傳入T::class.java。
如果我們想要啟動TestActivity,隻需要這樣寫就可以了
同時,可能intent會附帶一些參數,如下寫法
val intent = Intent(context, TestActivity::class.java)
intent.putExtra("param1","data")
intent.putExtra("param2",123)
context.startActivity(intent)
而通過上面的封裝,我們就沒法進行傳參了,但是我們可以通過高階函數類解決
inline fun <reified T> startActivity(context: Context, block: Intent.() -> Unit){
val intent = Intent(context, T::class.java)
intent.block()
context.startActivity(intent)
}
通過添加一個函數類型參數,這樣就可以在調用startActivity()函數時使用Lambda表達式為Intent傳參
startActivity<TestActivity>(context) {
putExtra("param1","data")
putExtra("param2",123)
}
協變和逆變
在開始學習協變和逆變之前,我們還得先了解一個約定。一個泛型類或者泛型接口中的方法,它的參數清單是接收資料的地方,是以可以稱它為in位置,而它的傳回值是輸出資料的地方,是以可以稱它為out位置,如下圖所示。
協變的定義:假如定義了一個MyClass的泛型類,其中A是B的子類型,同時MyClass又是MyClass
的子類型,那麼我們就可以稱MyClass在T這個泛型上是協變的。逆變的定義:假如定義了一個MyClass的泛型類,其中A是B的子類型,同時MyClass
又是MyClass的子類型,那麼我們就可以稱MyClass在T這個泛型上是逆變的。觀察如下代碼,我們在泛型T的聲明前面加上了一個out關鍵字。這就意味着現在T隻能出現在out位置上,而不能出現在in位置上,同時也意味着SimpleData在泛型T上是協變的。
class SimpleData<out T>(val data: T?) {
fun get(): T? {
return data
}
}
觀察如下代碼,我們在泛型T的聲明前面加上了一個in關鍵字。這就意味着現在T隻能出現在in位置上,而不能出現在out位置上,同時也意味着Transformer在泛型T上是逆變的。
interface Transformer<in T> {
fun transform(t: T): String
}
在out位置上,同時也意味着Transformer在泛型T上是逆變的。
interface Transformer<in T> {
fun transform(t: T): String
}