跟Java的泛型一样,Kotlin
的泛型也是用来限制其类型
class Test<T: CallBack> {
fun add(t: T){
t.run()
t.callback()
}
}
// 如果T继承了多个父类则使用where关键字
// where T:CallBack, T:Runnable表示T既是CallBack的子类又是Runnable的子类
class Test<T> where T:CallBack, T:Runnable{
fun add(t: T){
t.run()
t.callback()
}
}
reified真泛型
默认泛型是不支持访问泛型的类型的。使用reified
关键字,才能支持访问泛型的类型 。另外,带有reified
真泛型的函数必须是inline
内联函数,这个比较好理解,inline
将函数的代码拷贝到调用的地方,才能知道具体泛型的类型。
//带有reified的函数必须为内联函数
inline fun <reified T : Activity> Activity.start() {
// T::class.java T为真泛型 才能访问JVM类对象
startActivity(Intent(this, T::class.java));
}
inline fun <reified T> printIfTypeMatch(item: Any) {
if (item is T) { // 👈 这里就不会在提示错误了
println(item)
}
}
协变out与逆变in
Kotlin
的协变与逆变跟Java
的原理是一样。唯一的区别就是用关键字不同。
-
Koltin
使用关键字out
来支持协变,等同于Java
的上界通配符? extends
包括A
和A
的子类 -
Kotlin
使用关键字in
来支持逆变,等同于Java的下界通配符? super
包括A
和A
的父类
协变 out
表示,out A
表示是其类型A
的子类,其类型不确定,不支持修改,只能读取到基类A
。
裂变in
就反过来,in A
表示是A
的父类。基类不确定,不支持get。但是A
一定是这个未知类型的子类型,根据多态性,支持修改
// out
class Producer<T> {
fun produce(): T? {
return null
}
}
val producer: Producer<out TextView> = Producer<Button>()
val textView: TextView? = producer.produce()
// in
class Consumer<T> {
fun consume(t: T) {
}
}
val consumer: Consumer<in Button> = Consumer<TextView>()
consumer.consume(Button(context)) // 👈 相当于 'List' 的 'add'
在前面的例子中,在声明 Producer
的时候已经确定了泛型 T
只会作为输出来用,但是每次都需要在使用的时候加上 out TextView
来支持协变,写起来很麻烦。
Kotlin 提供了另外一种写法:可以在声明类的时候,给泛型符号加上 out
关键字,表明泛型参数 T
只会用来输出,在使用的时候就不用额外加 out
了。
class Producer<out T> {
fun produce(): T? {
return null
}
}
val producer: Producer<TextView> = Producer<Button>() // 👈 这里不写 out 也不会报错
val textView: TextView? = producer.produce()