【笔记】Kotlin的泛型
前言
Kotlin的泛型学习笔记
类中定义泛型
1 | class 类名<T> { |
1 | abstract class 类名<T> {} |
1 | interface 接口名<T> {} |
泛型作为属性类型
1 | class 类名<T> { |
泛型作为方法形参类型
1 | class 类名<T> { |
泛型作为方法返回值类型
1 | class 类名<T> { |
定义多个泛型
1 | class 类名<T, R> {} |
- 创建对象时忽略部分泛型类型
1 | class 类名<T, R> {} |
子类明确泛型类型
1 | open class 类名<T> { |
子类继承泛型类型
1 | open class 类名<T> { |
函数中定义泛型
1 | fun <T> 函数名() {} |
泛型作为函数形参类型
- 自动类型推导,省略显式指定函数泛型类型
1 | fun <T> 函数名(形参: T) {} |
泛型作为函数返回值类型
1 | fun <T> 函数名(): T {} |
泛型作为传入函数作为形参的类型
1 | fun <T> 函数名(形参名: (T) -> Unit) {} |
1 | fun <T> 函数名(形参名: () -> T) {} |
- 泛型作为扩展函数
1 | fun <T> 函数名(形参名: T.() -> Unit) {} |
抗变、逆变、协变
抗变(Invariant)
- 不通过关键字标记泛型类型时为抗变,抗变父子类不能相互转换
1 | var 变量名: 数据类型<泛型类型> = 值 |
逆变
- 通过
out关键字标记的泛型类型为逆变,逆变可以实现子类到父类的转换
1 | var 变量名1: 数据类型<out 泛型类型> = 值 |
协变
- 通过
in关键字标记的泛型类型为协变,协变可以实现父类到子类的转换
1 | var 变量名1: 数据类型<in 泛型类型> = 值 |
任何类型作为泛型类型
1 | var 变量名: 数据类型<*> = 值 |
1 | var 变量名: 数据类型<Any> = 值 |
为泛型指定类型上限
1 | fun <T : 上限类型> 函数名() {} |
- 默认泛型类型上限类型为
Any?
1 | fun <T> 函数名() {} |
1 | fun <T : Any?> 函数名() {} |
多个泛型
1 | fun <T, *> 函数名() {} |
1 | fun <*, T> 函数名() {} |
1 | fun <*, *> 函数名() {} |
类型擦除
泛型只能用于编译前,所以编译后是没有泛型的概念的,泛型
T会被编译为Any?,这就是类型擦除如果泛型存在上界,则类型擦除后会变成上限类型
1 | fun <T : 上限类型> 函数名() {} |
1 | fun <上限类型> 函数名() {} |
- 内联函数由于会在编译时确定泛型类型,所以内联函数不会发生类型擦除
1 | inline fun <T> 函数名() {} |
1 | fun <实际类型> 函数名() {} |
- 内联函数中,可以通过
reified具化泛型类型,以便在函数内部将泛型类型当作实际类型来使用
1 | inline fun <reified T> 函数名() { |