1、定義泛型接口、泛型類
泛型在定義類,接口,函數時使用泛型形參,這個泛型形參将在聲明變量、建立對象,調用方法時動态地指定(傳入實際的類型,也可稱為類型實參)
可以為任何類、接口增加泛型聲明
//定義App類時使用了泛型聲明
open class Apple<T>{
//使用泛型T定義屬性
open var info:T?
constructor(){
info=null
}
//使用泛型T來定義構造器
constructor(info:T){
this.info=info
}
}
fun main(args:Array<String>){
//由于傳給泛型T的是String,所有構造器的參數隻能是String
var a1:Apple<String> = Apple<String>("蘋果")
//由于傳給泛型T的是Int,所有構造器的參數隻能是Int
var a2:Apple<Int> = Apple(3)
//由于傳給泛型T的是Double,系統推斷泛型形參為Double類型
var a3=Apple(5.67)
println(a1.info)
println(a2.info)
println(a3.info)
}
列印:
蘋果
3
5.67
2、從泛型派生子類
當建立了帶泛型聲明的接口、父類之後,可以為該接口建立實作類,或者從該父類派生子類。
當使用這些接口,父類時不能再包含泛型形參。
父類形參為泛型形參,子類應當明确泛型形參的具體類型
//定義App類時使用了泛型聲明
open class Apple<T>{
//使用泛型T定義屬性
open var info:T?
constructor(){
info=null
}
//使用泛型T來定義構造器
constructor(info:T){
this.info=info
}
}
class A1:Apple<String>(){
//正确重寫了父類的屬性,屬性類型與父類Apple<String>的屬性類型完全相同
override var info:String?=null
get() = "子類"+super.info
}
fun main(args:Array<String>){
var a1:A1=A1()
println(a1.info)
}
列印
子類null
3、泛型型變的需要(實際就是轉型,便于添加一個類型的集合到另外一個類型的集合裡)
型變實際就是轉型,便于添加一個類型的集合到另外一個類型的集合裡。
java是通過通配符?來完成的。但通配符的上限是Object類
泛型存在如下規律
通配符上限(泛型協變)意味着從中取出(out)對象是安全的,但傳入對象(in)則不可靠
通配符下限(泛型逆變)意味着想起傳入(in)對象是安全的。但取出對象(out)則不可靠
kotlin抛棄了泛型通配符文法,而是利用in,out讓泛型支援型變
4、聲明處型變
kotlin處理型變的規則
- 如果泛型隻需要出現在方法的傳回值聲明中(不出現在形參聲明中),那麼該方法就隻是取出泛型對象,是以該方法就支援泛型協變(相當于通配符上限);如果一個類的所有方法都支援泛型協變,那麼該類的泛型參數就可以使用out修飾
- 如果泛型值需要出現在方法的形參聲明中(不出現在傳回值聲明中),那麼該方法就隻是傳入泛型對象,是以該方法就支援泛型逆變(相當于通配符下限);如果一個類的所有方法都支援泛型逆變,那麼該類的泛型參數可以用in修飾
支援協變的案例
class User<out T>{
//此處不能用var,否則就有setter方法,setter方法會導緻T出現在方法形參中
val info:T
constructor(info:T){
this.info=info
}
fun test():T{
println("執行test方法")
return info
}
}
fun main(args:Array<String>){
//此時T的類型是String
var user=User<String>("瘋狂教育體系")
println(user.info)
//對于u2而言,她的類型是User<Any>,此時T的類型是Any,由于程式聲明了T支援協變,是以User<String>可當成User<Any>使用
var u2:User<Any> = user//取出資料,所有将上限傳入小類型是可行的
println(u2.info)
}
列印:
瘋狂教育體系
瘋狂教育體系
支援逆變的案例
class Item<in T>{
fun foo(t:T){
println(t)
}
}
fun main(args:Array<String>){
//此時T的類型是Any
var item=Item<Any>()
item.foo(20)
var im2:Item<String> =item
//im2的實際類型是Item<Any>,是以她的foo的參數隻要是Any即可
//但我們聲明了im2的類型為Item<String>,是以傳入的參數值可能是String,是以程式肯定是安全
im2.foo("瘋狂kotlin講義")
}
列印
20
瘋狂kotlin講義
kotilin處理規則
- 如果泛型T隻出現在該類的方法的傳回值聲明中,那麼該泛型參數形參即可使用out修飾T
- 如果泛型T隻出現在該類的方法的形參聲明中,那麼該泛型參數即可使用in修飾T
泛型在參數聲明的時候出現,這是聲明處型變
5、使用處型變:類型投影
聲明處型變導緻此類所有方法都要用泛型聲明傳回值類型
使用處型變就是在使用泛型時對其使用out或in修飾
看不下去了,過吧