泛型基本概念
泛型基础概念
- 一种类型层面抽象
- 通过泛型参数实现构造更加通用的类型的能力
- 可以让符合继承关系的类型批量实现某些能力
泛型基本声明
//函数声明
fun <T> maxOf(a: T, b: T): T {
TODO()
}
//类声明
public class List<T> {
TODO()
}
泛型使用
val max : String = maxOf<String>("Hello", "World")
val list:List<String> = List<String>()
泛型约束
例子
fun <T : Comparable<T>> maxOf(a: T, b: T): T {
return if (a > b) a else b
}
多个约束
需要使用where
,用,
隔开
fun <T, R> callMax(a: T, b: T): R
where T : Comparable<T>, T : () -> R,
R : Number {
return if (a > b) a() else b()
}
泛型形变
主要有三种:不变
,协变
,逆变
-
不变
:没有继承关系 -
协变
:继承关系一致 -
逆变
:继承关系相反
协变
使用 out
使得一个类型参数协变,协变类型参数只能用作输出,可以作为返回值类型但是无法作为入参的类型
协变点:函数返回值类型就是泛型参数
//书总类
interface Book
//教育书
interface EduBook : Book
//书店
class BookStore<out T : Book> {
fun getBook(): T {
TODO()
}
}
说明:书可以从教育书店和总书店买到,但是教育书一般只能是教育书店买,总书店买的不一定是
逆变
使用in
使得一个类型参数逆变,逆变类型参数只能用作输入,可以作为入参的类型但是无法作为返回值的类型
逆变点:函数参数类型为泛型类型
//垃圾总类
open class Waste
//干垃圾类
class DryWaste : Waste()
//垃圾桶
class Dustbin<in T : Waste> {
fun put(t: T) {
TODO()
}
}
说明:垃圾桶能放干垃圾和所有的垃圾,干垃圾桶只能放干垃圾
星投影
介绍
我们可以使用*
替代我们的泛型参数
*
可用在变量类型声明位置*
可以描述一个未知类型*
替换类型:协变点返回泛型参数上限类型;逆变点接受参数下限类型;所有类型的下限都是Nothing
举例:
Function<*, String> , 代表 Function<in Nothing, String> ;
Function<Int, *> , 代表 Function<Int, out Any?> ;
Function<, > , 代表 Function<in Nothing, out Any?>
适用范围
*
不能直接用在属性或者函数上
//错误 间接作用属性上
QueryMap<String,*>()
//错误 直接作用到函数上
maxOf<*>(1,2)
*
适用于类型描述场景
val queryMap: QueryMap<*, *> = QueryMap<String, Int>()
queryMap.getKey()
queryMap.getValue()
val f: Function<*, *> = Function<Number, Any>()
//泛型擦除
if (f is Function) {
(f as Function<Number, Any>).invoke(1, Any())
}
//这个比较特殊
HashMap<String, List<*>>()
泛型的实现类和内联特化
伪泛型:编译时擦除类型,运行时无实际类型生成
解决办法:声明内联函数
我们在使用Gson
反序列化的时候,一般我们是这样使用的
public <T> T fromJson( Stirng json, Class<T> class){
...
}
使用内联特化后就可以不传这个Class
inline fun <reified T> Gson.fromJson(json: String): T
= fromJson(json, T::class.java)
//类型推导
val person: Person = gson.fromJson("""{}""")
//泛型参数
val person2 = gson.fromJson<Person>("""{}""")
案例
typealias OnConfirm = () -> Unit
typealias OnCancel = () -> Unit
private val EmptyFunction = {}
open class Notification(
val title: String,
val content: String
)
class ConfirmNotification(
title: String,
content: String,
val onConfirm: OnConfirm,
val onCancel: OnCancel
) : Notification(title, content)
interface SelfType<Self> {
val self: Self
get() = this as Self
}
open class NotificationBuilder<Self: NotificationBuilder<Self>>: SelfType<Self> {
protected var title: String = ""
protected var content: String = ""
fun title(title: String): Self {
this.title = title
return self
}
fun content(content: String): Self {
this.content = content
return self
}
open fun build() = Notification(this.title, this.content)
}
class ConfirmNotificationBuilder : NotificationBuilder<ConfirmNotificationBuilder>() {
private var onConfirm: OnConfirm = EmptyFunction
private var onCancel: OnCancel = EmptyFunction
fun onConfirm(onConfirm: OnConfirm): ConfirmNotificationBuilder {
this.onConfirm = onConfirm
return this
}
fun onCancel(onCancel: OnCancel): ConfirmNotificationBuilder {
this.onCancel = onCancel
return this
}
override fun build() = ConfirmNotification(title, content, onConfirm, onCancel)
}
fun main() {
ConfirmNotificationBuilder()
.title("Hello")
.onCancel {
println("onCancel")
}.content("World")
.onConfirm {
println("onConfirmed")
}
.build()
.onConfirm()
}