kotlin学习笔记——泛型及reified函数
生活随笔
收集整理的這篇文章主要介紹了
kotlin学习笔记——泛型及reified函数
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
kotlin中的泛型與java中的差不多
class TypedClass<T>(param : T){...
}val s = TypedClass<String>("hello")
kotlin中可以簡化模板代碼,編譯器可以自動推斷類型,如 val s = TypedClass("hello")
但如果接收一個null,編譯器無法推斷類型,仍然需要指定類型,如
val s = TypedClass<String?>(null)
我們可以給泛型添加限制,如:
class TypeClass<T : Any>(param : T){...
}
這時限制為非null類型,上面接收null的代碼就會報錯了。
我們也可以限制為某種類型的子類,與java中類似,如
class TypedClass<T : Context>(param : T){....
} 這樣所有繼承至Context的類可以使用,其他則不能。
泛型也可以使用在函數(shù)中,如
fun <T> do(param : T) List<T>{...
}
泛型的變體 在java中,使用泛型時會遇到一些問題,比如使用集合的時候,如 List<String> list1 = Lists.newArrayList(); List<Object> list2 = list1 就會報錯,雖然List<Object>有更弱的限制,因為如果編譯器允許這種行為,后面如果出現(xiàn)下面的代碼就一定會程序崩潰。 list2.add(5); String s = list2.get(0); 但是在java中,我們可以使用addAll,如 List<Object> list2 = Lists.newArrayList(); list2.addAll(list1) 這時因為addAll的函數(shù)接收的參數(shù)是“Collection<? extends E> items”,這里就用到了泛型的協(xié)變。 為了解決類似的問題,為泛型增加了通配符,包括協(xié)變和逆變 協(xié)變(covariance)——?“? extends XXX” —— 表示限制為XXX及其子類 逆變(contravatiance)—— “? super XXX” —— 表示限制為XXX及其父類 這樣就可以處理上面List的問題,如 List<? extends Object> list2 = list1; 但是通配符都有它的限制,通配符定義的了使用場景變體(use-site variance),當我們使用它的時候都需要聲明它。這表示我們每次聲明一個泛型變量都需要增加模板代碼。例如上面的代碼就增加了一下額外的模板代碼。 在kotlin中,我們可以使用內部聲明變體(declaration-site variance)這種更簡單的方式,來表示當我們定義一個類或接口時可以處理弱限制場景。 相比冗長的通配符,在kotlin中我們可以使用“out”來針對協(xié)變,使用“in”來針對逆變。如 class TypedClass<out T>{... }val obj1 = TypedClass<String>() val obj2 : TypedClass<Any> = obj1 這段代碼可以在kotlin中編譯運行(最后一行實際上就相當于val obj2 : TypedClass<? extends Any> = obj1)
下面我們再來說說reified函數(shù),它與泛型密切相關 比如我們啟動一個activity代碼: val intent = Intent(MainActivity@this, javaClass<DetailActivity>) intent.putExtra(DetailActivity.ID, item.id) intent.putExtra(DetailActivity.NAME, item.name) startActivity(intent) anko給我們提供了一個reified function,可以更簡單的實現(xiàn) startActivity<DetailActivity>(DetailActivity.ID to item.id, DetailActivity.NAME to item.name) 我們知道在java中使用泛型的時候,無法通過泛型來得到Class,一般我們會將Class通過參數(shù)傳過去。 在kotlin中一個內聯(lián)函數(shù)(inline)可以被具體化(reified),這意味著我們可以得到使用泛型類型的Class。 startActivity的源碼如下: public?inline?fun?<reified?T:?Activity>?Context.startActivity(vararg?params:?Pair<String,?String>)?{val?intent?=?Intent(this,?T::class.javaClass)params?forEach?{?intent.putExtra(it.first,?it.second)?}startActivity(intent) } 可以看到使用T::class.javaClass就可以得到使用泛型類型的Class。 startActivity是Context的內聯(lián)函數(shù),所以要在Context類中才可以使用,在其他地方使用則需要使用with函數(shù): with(context){startActivity<...>(...) }
泛型的變體 在java中,使用泛型時會遇到一些問題,比如使用集合的時候,如 List<String> list1 = Lists.newArrayList(); List<Object> list2 = list1 就會報錯,雖然List<Object>有更弱的限制,因為如果編譯器允許這種行為,后面如果出現(xiàn)下面的代碼就一定會程序崩潰。 list2.add(5); String s = list2.get(0); 但是在java中,我們可以使用addAll,如 List<Object> list2 = Lists.newArrayList(); list2.addAll(list1) 這時因為addAll的函數(shù)接收的參數(shù)是“Collection<? extends E> items”,這里就用到了泛型的協(xié)變。 為了解決類似的問題,為泛型增加了通配符,包括協(xié)變和逆變 協(xié)變(covariance)——?“? extends XXX” —— 表示限制為XXX及其子類 逆變(contravatiance)—— “? super XXX” —— 表示限制為XXX及其父類 這樣就可以處理上面List的問題,如 List<? extends Object> list2 = list1; 但是通配符都有它的限制,通配符定義的了使用場景變體(use-site variance),當我們使用它的時候都需要聲明它。這表示我們每次聲明一個泛型變量都需要增加模板代碼。例如上面的代碼就增加了一下額外的模板代碼。 在kotlin中,我們可以使用內部聲明變體(declaration-site variance)這種更簡單的方式,來表示當我們定義一個類或接口時可以處理弱限制場景。 相比冗長的通配符,在kotlin中我們可以使用“out”來針對協(xié)變,使用“in”來針對逆變。如 class TypedClass<out T>{... }val obj1 = TypedClass<String>() val obj2 : TypedClass<Any> = obj1 這段代碼可以在kotlin中編譯運行(最后一行實際上就相當于val obj2 : TypedClass<? extends Any> = obj1)
下面我們再來說說reified函數(shù),它與泛型密切相關 比如我們啟動一個activity代碼: val intent = Intent(MainActivity@this, javaClass<DetailActivity>) intent.putExtra(DetailActivity.ID, item.id) intent.putExtra(DetailActivity.NAME, item.name) startActivity(intent) anko給我們提供了一個reified function,可以更簡單的實現(xiàn) startActivity<DetailActivity>(DetailActivity.ID to item.id, DetailActivity.NAME to item.name) 我們知道在java中使用泛型的時候,無法通過泛型來得到Class,一般我們會將Class通過參數(shù)傳過去。 在kotlin中一個內聯(lián)函數(shù)(inline)可以被具體化(reified),這意味著我們可以得到使用泛型類型的Class。 startActivity的源碼如下: public?inline?fun?<reified?T:?Activity>?Context.startActivity(vararg?params:?Pair<String,?String>)?{val?intent?=?Intent(this,?T::class.javaClass)params?forEach?{?intent.putExtra(it.first,?it.second)?}startActivity(intent) } 可以看到使用T::class.javaClass就可以得到使用泛型類型的Class。 startActivity是Context的內聯(lián)函數(shù),所以要在Context類中才可以使用,在其他地方使用則需要使用with函數(shù): with(context){startActivity<...>(...) }
?
總結
以上是生活随笔為你收集整理的kotlin学习笔记——泛型及reified函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: kotlin学习笔记——接口与委托
- 下一篇: kotlin学习笔记——单元测试