首先申明下,本文为笔者学习《Kotlin 程序开发入门精要》的笔记,并加入笔者自己的理解和归纳总结。
1. 泛型
所谓泛型,就是指在定义数据结构时,只指定类型的占位符,待到使用该数据结构时再指定具体的数据类型。
定义泛型类型变量,可以完整地写明类型参数,如果编译器可以自动推定类型参数,也可以省略类型参数。
class Data<T>(v: T) {
var value = v
}
fun main(args: Array<String>) {
// 创建类的实例时指定类型参数
var strData: Data<String> = Data("Hello World")
// 编译器会进行类型推断
var intData = Data(12)
println(strData.value) // Hello World
println(intData.value) // 12
}
2. 泛型函数
泛型函数的类型参数要放在函数名的前面。
fun <T> copy(d: Data<T>): Data<T> {
return Data(d.value)
}
3. 泛型约束
泛型约束常见的是上界约束,类似于Java的extends
关键字,在冒号(:)
后面指定的类型就是泛型参数的上界。如果没有指定,则默认使用的上界类型是Any?
。
fun <T : Comparable<T>> equals(v1: T, v2: T): Boolean {
return v1.compareTo(v2) == 0
}
fun main(args: Array<String>) {
println(equals(1, 1)) // true
println(equals(1, 2)) // false
}
在定义泛型的尖括号<>
内,只允许定义唯一一个上界,如果需要指定多个上界,使用单独的where
子句。
interface ICopy<T> {
fun copy(): T
}
fun <T> copy(t: T) : T
where T : Comparable<T>, T : ICopy<T> {
return t.copy()
}
4 . 类型变异
kotlin泛型没有提供通配符,取而代之的是out
和in
关键字。
用out
声明的泛型占位符只能在获取泛型类型值的地方,如函数的返回值。
class OutData<out T>(val v: T) {
fun getValue(): T {
return v
}
}
fun main(args: Array<String>) {
var strData = OutData<String>("Hello World")
var objData: OutData<Any> = OutData("Object")
objData = strData // OutData<String>可以看做OutData<Any>的子类
}
用in
声明的泛型占位符只能在设置泛型值的地方,如函数的参数。
class InData<in T>() {
fun setValue(t: T) {
}
}
fun main(args: Array<String>) {
var intData = InData<Int>()
var anyData = InData<Any>()
intData = anyData // InData<Any>可以看做InData<Int>的子类
}
5. 类型投射
类A
是类B
的父类,但Array<A>
和Array<B>
不是继承关系,out
和in
关键字可以对类型投射。
open class A{}
class B : A() {}
fun copy(from: Array<out A>, to: Array<A>) {
}
fun fill(dest: Array<in B>, v: B) {
}
fun main(args: Array<String>) {
var aArr: Array<A> = arrayOf(A(), A())
var bArr: Array<B> = arrayOf(B(), B())
copy(bArr, aArr)
fill(aArr, B())
}
- Kotlin 中的
out A
类似于 Java 中的? extends A
,即泛型参数类型必须是A或者A的子类,用来确定类型的上限
- Kotlin 中的
in B
类似于 Java 中的? super B
,即泛型参数类型必须是B或者B的父类,用来确定类型的下限
当我们不知道泛型参数的类型信息时,但仍需要安全的使用它时,可以使用星投影,用星号*
表示。如果类型定义为interface Function<in T, out U>
,那么可以出现以下几种信号投射。
Function<*, String>,代表Function<in Nothing, String>
Function<Int, *>,代表Function<Int, Out Any?>
Function<*, *>,代表Function<in Nothing, Out Any?>