- 泛型
- 泛型约束:我们可以使用泛型约束来设定一个给定参数允许使用的类型,Kotlin 中使用 : 对泛型的的类型上限进行约束。最常见的约束是上界(upper bound), 默认的 上界是 Any?
//T就是上界 Comparable 的子类型可以替代 T
fun <T : Comparable<T>> sort(list: List<T>) {
// ……
}
- 型变:Kotlin 中没有通配符类型,它有两个其他的东西:声明处型变与类型投影。
- 声明处的类型变异使用协变注解修饰符:in、out,消费者 in, 生产者 out。 使用 out 使得一个类型参数协变,协变类型参数只能用作输出,可以作为返回值类型但是无法作为入参的类型
- in 使得一个类型参数逆变,逆变类型参数只能用作输入,可以作为入参的类型但是无法作为返回值的类型
- 类型投影:使用处型变 和 星投影,使用处型变就是在函数参数处使用型变来控制错误的发生。
- java 中的通配符类型参数: ? extends E
- 通配符<? extends E>表示包括E在内的所有子类,称为协变
- 通配符<? super E>表示包括E在内的所有父类,称为逆变
- 协变: 表示包括E在内的所有子类,泛型对象只能读取,称为生产者
- 逆变: 表示包括E在内的所有父类,泛型对象只能写入,称为消费者
- Kotlin的泛型使用基本和Java一致
- Java的<? extends T> 相当于 Kotlin的 ,Java的<? super T> 相当于 Kotlin的
- 只能生产(出参), 只能消费(入参)
- 只能生产的原因是编译器无法确认什么对象符合那个未知的 T 的子类型,只知道一定返回T, 只能消费的原因是无法确认T超类的具体类型
- <>相当于java中的无泛型。对于 Foo ,其中 T 是一个具有上界的协变类型参数,Foo <> 等价于 Foo ;对于 Foo ,其中 T 是一个逆变类型参数,Foo <*> 等价于 Foo
- 先看下面的代码
class Book<in T>{
fun getType(a:T) {
}
fun getName() {
}
}
open class Bar<out T> {
fun getType():T?{
return null
}
}
fun getType(a: Bar<*>,b:Book<*>) {
val c = a.getType()
c.toString()// 这个时候c是Any的类型
b.getName()
b.getType( )//错误 ,括号里面无论传什么都是错的,也就是会所b的getType函数是不能使用的
}
在结合泛型文档,就应该很快明白了。