類型參數
泛型允許定義帶類型形參的類型,當這種類型的實例被創建出來的時候,類型形參被替換成稱爲類型實參的具體類型
實例
// 源碼listOf函數聲明
fun <T> listOf(vararg elements: T): List<T>
val list=listOf("hello","world") // 編譯器推導
val list= listOf<String>()// 顯示說明
上例中 T 爲類型形參 ,並且函數的返回類型使用了類型形參
區別
- Kotlin 要求類型實參要麼被顯示地說明,要麼能被編譯器推導推導出來
- Kotlin 不支持原生態類型,類型實參必須定義
- Java 允許使用沒有類型參數的泛型類型(原生態類型),因爲支持老版本代碼兼容
泛型類和函數
泛型類
Kotlin 通過在類名稱後加上一對尖對號,並把類型參數放在尖對號內來聲明泛型類及泛型接口。一旦聲明之後,就可以在類的主體內像其他類型一樣使用類型參數。
// 泛型類
class Gen<T>(private var t: T) {
fun getValue() :T{
return t
}
}
// 泛型接口
interface List<T>{
public operator fun get(index: Int): T
}
小結: 如果類繼承了泛型類(實現了泛型接口),就得爲基礎類型的泛型形參提供了一個類型實參,它可以是具體類型或者另一個類型形參:
class GenList:List<String>{
override fun get(index :Int):String=...
}
class ArrayList<T>:List<T>{
override fun get(index :Int):T=...
}
泛型函數
泛型函數有它自己的類型形參,這些類型形參在每次函數調用時都必須替換成具體的類型實參
fun <T> printMessage(msg :T){
when (content) {
is Int ->{"該信息數據類型是整型"}
else ->{"該信息數據類型不是整型"}
}
}
注意: 普通(即非拓展)屬性不能擁有類型參數,不能在一個類的屬性中存儲多個不同類型的值,因此聲明泛型非拓展函數沒有任何意義
類型參數約束
類型參數約束可以限制作爲泛型類和泛型函數的類型實參的類型;如果把一個類型指定爲泛型類型形參的上界約束,在泛型類型具體的初始化中,其對應的類型實參就必須是這個具體類型或者它的子類型
示例
// 函數聲明
fun <T:Number> List<T>.sum() :T
// 具體類型實參繼承了Number,函數調用是允許的
println(listOf(1,2,3).sum())
上例中,通過在類型參數後指定上界來定義約束,把冒號放在類型參數名稱之後,作爲類型形參上界的類型緊隨其後;一旦指定了類型形參T的上界,就可以把類型T的值當作它的上界(類型)的值使用
類型參數非空、可空
如果聲明的是泛型類或者泛型函數,任何類型實參,包括那些可空的類型實參,都可以替換它的類型形參;沒有指定上界的類型形參將會使用Any?這個默認上界
// 類型參數可空 默認上界的類型形參是Any?
class Person<T>{
fun name(value :T){
value?.hashcode()
}
}
// 類型參數非空 默認上界的類型形參是Any
class Person<T:Any>{
fun name(value :T){
value?.hashcode()
}
}
注意:可以通過指定任意非空類型作爲上界,來讓類型參數非空,不光是類型Any