/**
* 泛型類
*/
class Animal<T> {}
/**
* 泛型接口
* @param T
*/
interface IAnimal<T> {
fun <T> initAnimal(p: T)
}
//泛型約束
//泛型約束表示我們可以指定泛型類型(T)的上界,
//即父類型髓需,默認的上界為Any?,如果只有一個上界可以這樣指定
fun <T : Animal<T>> init(p: T) {}
//如果需要指定多個上界類型,就需要使用where語句:
fun <T> initA(p: T) where T : Animal<T>, T : IAnimal<T> {}
//類型擦除
//Kotlin 為泛型聲明執(zhí)行的類型安全檢測僅在編譯期進行淘太,
運行時實例不保留關(guān)于泛型類型的任何信息行嗤。這一點在 Java 中也是類似的。
//
//例如砚偶,Array<String>挪钓、Array<Int>的實例都會被擦除為Array<*>是越,
//這樣帶來的好處是保存在內(nèi)存中的類型信息也就減少了。
//
//由于運行時泛型信息被擦除碌上,所以在運行時無法檢測一個
//實例是否是帶有某個類型參數(shù)的泛型類型倚评,
//所以下面的代碼是無法通過編譯的
(Cannot check for instance of erased type: Array<Int>):
//fun isArrays(a: Any) {
// if (a is Array<Int>) {
// println("is array")
// }
//}
//但我們可以檢測一個實例是否是數(shù)組,
//雖然 Kotlin 不允許使用沒有指定類型參數(shù)的泛型類型馏予,
//但可以使用星投影*(這個后邊會說到):
fun isArray(a: Any) {
if (a is Array<*>) {
println("is array")
}
}
//同樣原因天梧,由于類型被擦除,我們也無法安全
//的將一個實現(xiàn)轉(zhuǎn)換成帶有某個類型參數(shù)的泛型類型:
fun sumArray(a: Array<*>) {
val intArray = a as? Array<Int> ?: throw IllegalArgumentException("Array的泛型類型必須是Int類型")
println(intArray.sum())
}
//因為我們無法判斷數(shù)組a的是不是Array<Int>類型的霞丧,
//所以可能會出現(xiàn)異常的情況呢岗。
//
//對于泛型函數(shù),如果在函數(shù)內(nèi)需要使用具體的泛型類型蛹尝,
//同樣由于運行時泛型信息被擦除的原因后豫,
//你無法直接使用它(Cannot check for instance of erased type: T):
//fun < T> test(param: Any) {
// if (param is T){
// println("param type is match")
// }
//}
//但還是有辦法的,可以用inline關(guān)鍵字修飾函數(shù)突那,
//即內(nèi)聯(lián)函數(shù)挫酿,這樣編譯器會把每一次函數(shù)調(diào)用都換成函數(shù)實際代碼實現(xiàn),
//同時用reified關(guān)鍵字修飾泛型類型陨收,這樣就能保留泛型參數(shù)的具體類型了:
inline fun <reified T> test(param: Any) {
if (param is T) {
println("param type is match")
}
}
//型變
//1饭豹、聲明處型變
//型變是泛型中比較重要的概念,首先我們要知道 Kotlin 中
//的泛型是不型變的务漩,這點和 Java 類似。那什么是型變呢它褪,看個例子:
open class A
class B : A()
fun text() {
val arrayB: Array<B> = arrayOf(B(), B())
//val arrayA:Array<A> = arrayB
// 你會發(fā)現(xiàn)第二個賦值語句會有錯誤提示饵骨,
//Type mismatch. Required:Array<A> Found:Array<B>類型不匹配,
// Array<B>并不是Array<A>的子類茫打,
就是因為 Kotlin 中的泛型是默認不型變的居触,
無法自動完成類型轉(zhuǎn)換,但B是A的子類老赤,
// 這個賦值操作本質(zhì)上是合理的轮洋、安全的,
//但編譯器似乎并不知道抬旺,這必然給我們開發(fā)過程中帶來了麻煩
// 為什么Array無法正常的賦值弊予,而List、Set开财、
//Map可以呢汉柒?如下代碼误褪,編譯器不會有錯誤提示的:
//
// val list1: List<B> = listOf(B(), B(), B())
// val list2: List<A> = list1
// 我們可以對比一下Array和List在源碼中的定義:
//
// public class Array<T> {}
//
// public interface List<out E> : Collection<E> {}
// 可以看到List的泛型類型使用了out修飾符,這就是關(guān)鍵所在了碾褂。
//這就是 Kotlin 中的聲明處型變兽间,用來向編譯器解釋這種情況。
//
// 關(guān)于out修飾符我們可這樣理解正塌,當(dāng)類嘀略、
//接口的泛型類型參數(shù)被聲明為out時,
//則該類型參數(shù)是協(xié)變的乓诽,泛型類型的子類型是被保留的屎鳍,
// 它只能出現(xiàn)在函數(shù)的輸出位置,只能作為返回類型问裕,
//即生產(chǎn)者逮壁。帶來的好處是,A是B的父類粮宛,
那么List<A>可以是List<B>的父類窥淆。
// 我們修改下上邊List賦值的代碼:
val list1: List<A> = listOf(A(), A(), A())
// val list2: List<B> = list1
// 即反過來賦值,由于B并不是A的父類巍杈,
//會有Type mismatch. Required:List<B> Found:List<A>錯誤提示忧饭。
// 為了應(yīng)對這種情況,Kotlin 還提供了一個in修飾符筷畦。
// 關(guān)于in修飾符我們可這樣理解词裤,當(dāng)類、接口的泛型類型參數(shù)被聲明為in時鳖宾,
//則該類型參數(shù)是逆變的吼砂,泛型類型的父類型是被保留的,
// 它只能出現(xiàn)在函數(shù)的輸入位置鼎文,作為參數(shù)渔肩,只能作為消費類型,即消費者拇惋。
// 其實 Kotlin 中的Comparable接口使用了in修飾符:
// 寫一個測試函數(shù)周偎,編譯器并不會報錯:
fun test(a: Comparable<A>) {
val b: Comparable<B> = a
}
// 所以in修飾符和out修飾符的作用看起來的相對的,
//A是B的父類撑帖,那么Comparable<B>可以是Comparable<A>的父類蓉坎,體會下區(qū)別。
// 那么在 Kotlin 中我們自然想到的是型變修飾符了:
//
// Kotlin 中的out A類似于 Java 中的? extends A胡嘿,
//即泛型參數(shù)類型必須是A或者A的子類蛉艾,用來確定類型的上限
// Kotlin 中的in A類似于 Java 中的? super A,
//即泛型參數(shù)類型必須是B或者B的父類,用來確定類型的下限
}
kotlin泛型
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載伺通,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者箍土。
- 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屁药,“玉大人粥血,你說我怎么就攤上這事∧鸺” “怎么了复亏?”我有些...
- 文/不壞的土叔 我叫張陵,是天一觀的道長缭嫡。 經(jīng)常有香客問我缔御,道長,這世上最難降的妖魔是什么妇蛀? 我笑而不...
- 正文 為了忘掉前任耕突,我火速辦了婚禮,結(jié)果婚禮上评架,老公的妹妹穿的比我還像新娘眷茁。我一直安慰自己,他們只是感情好古程,可當(dāng)我...
- 文/花漫 我一把揭開白布蔼卡。 她就那樣靜靜地躺著,像睡著了一般挣磨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荤懂,一...
- 文/蒼蘭香墨 我猛地睜開眼女轿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了壕翩?” 一聲冷哼從身側(cè)響起蛉迹,我...
- 正文 年R本政府宣布唠亚,位于F島的核電站链方,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏灶搜。R本人自食惡果不足惜祟蚀,卻給世界環(huán)境...
- 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望割卖。 院中可真熱鬧前酿,春花似錦、人聲如沸鹏溯。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽丙挽。三九已至肺孵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颜阐,已是汗流浹背平窘。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- 一敲董、泛型及泛型約束 kotlin中的泛型紫皇,和java中思維大體是相同的,但又有些區(qū)別 用法和java沒什么兩樣腋寨。聪铺。...
- 類型擦除 泛型在編譯后類型會被擦除,所以在程序運行時候我們是不知道泛型的信息的萄窜。這里不知道泛型的信息聽起來可能會有...
- 場景跟 Java ?樣铃剔,不過?法有?點不?樣; Java 的 <? extends> 在 Kotlin ?寫作 <...
- 約束的定義多個約束查刻,where的使用多個泛型參數(shù)對比Java約束 一键兜、約束的定義 ??當(dāng)一個泛型參數(shù)沒有任何約束時...
- Java泛型 學(xué)習(xí)并掌握泛型類和泛型接口定義和使用 學(xué)習(xí)并掌握泛型函數(shù)的定義和使用 很清晰明了的使用教程 Kotl...