系列文章路引 👀 https://blog.csdn.net/weixin_44235109/article/details/119680974
文章目录
一、泛型的基本概念
泛型的概念
- 泛型是一种类型层面的抽象
- 泛型通过泛型参数实现构造更加通用的类型能力
- 泛型可以让符合继承关系的类型批量实现某些功能
泛型的基本声明方式
简单例子:
定义函数,比较任意类型的大小 <T> 表示声明的泛型类型
inline fun <T> maxOf( a : T , b : T) : T
定义类,任意类型的列表 <T> 表示声明的泛型类型
注意:第一个List和 下面 Cons继承的List 这两个T,不一样,下面的是Cons类自己的泛型,然后传给它继承的List,即调用父类构造器传上去的
sealed class DataList<T>{
object NIL:DataList<Nothing>()
data class Cons<T>(val head : T,val tail :DataList<T>) : DataList<T>()
}
//也可以写为
sealed class DataList<T>{
object NIL:DataList<Nothing>()
data class Cons<R>(val head : R,val tail :DataList<R>) : DataList<R>()
}
二、泛型约束
一般约束
可以直接在声明的泛型前面使用 “:” 加上被约束的类型,
比如我们完善一下上面说到的比较任意类型的大小。增加一个Comparable类型的约束,这么就可以直接在代码里面进行比较了。
fun <T : Comparable<T>> maxOf(a: T, b: T): T {
return if (a > b) a else b
}
//使用
val value1 = maxOf(1, 2)
val value2 = maxOf(2.0, 3.0)
val value3 = maxOf("s", "ss")
使用where关键字实现多个约束
可以在声明后面增加where关键字,进行多条件约束
多个约束实现
fun <T> callMax(a : T,b : T) where T : Comparable<T> , T : () -> Unit{
if (a > b) a else b
}
多个泛型参数实现
fun <T , R> callMax(a : T,b : T) : Rwhere T : Comparable<T> , T : () -> R{
if (a > b) a else b
}
例子:多个泛型参数,K要求可以被序列化,V要求可以比较
class MyMap<K,V> where k:Serializable, V:Comparable<V>
三、泛型形变
泛型形变三种形式
不变:<T> T前面没有任何的修饰
协变:<out T> T前面使用out修饰,out表示协变
逆变:<in T> T前面使用in修饰,in表示逆变
不变
T前面没有任何的修饰
注意此时:
List<Nothing>不是List<T>子类
List.NIL也不是List<T>的子类
sealed class DataList<T>{
object NIL:DataList<Nothing>()
...
}
协变
T前面使用out修饰,out表示协变
sealed class DataList<out T> {
fun test():T {
TODO()
}
}
- 子类Derived兼容父类Base
- 生产者Producer<Derived>兼容Producer<Base>
- 存在协变点的类的泛型参数必须声明为协变或者不变
- 当泛型类作为泛型参数类实例的生产者时用协变
逆变
T前面使用in修饰,in表示逆变
这里直接拿kotlin Comparable接口的源码给大家看了
public interface Comparable<in T> {
/**
* Compares this object with the specified object for order. Returns zero if this object is equal
* to the specified [other] object, a negative number if it's less than [other], or a positive number
* if it's greater than [other].
*/
public operator fun compareTo(other: T): Int
}
- 子类Derived兼容父类Base
- 生产者Consumer<Derived>兼容Consumer<Base>
- 存在逆变点的类的泛型参数必须声明为逆变或者不变
- 当泛型类作为泛型参数类实例的消费者时用逆变
UnSafeVariance
协变用到逆变点或者逆变用到协变点,可以使用@UnsafeVariance做保证
sealed class TList<out T>{
operator fun compareTo(other:@UnsafeVariance T):Int{
return 1
}
}
sealed class TList<in T>{
fun test():@UnsafeVariance T{
TODO()
}
}
违反形变约束的安全前提:
- 声明为协变的类出现逆变点或者相反
- 声明为不变的类接收逆变或协变的类型参数
- 泛型参数协变,逆变点不能引起修改,即始终只读不写
- 泛型参数逆变,协变点不得外部获取,即始终只写不读
四、星投影 Star Projection
星投影
- ‘*’ 可用在变量类型声明的位置
- ‘*’ 可用以描述一个未知的类型
- ‘*’ 所替换的类型在:协变点返回参数的上限类型;逆变点接收泛型参数的下限类型。
协变点的使用
class QueryMap<out K : CharSequence, out V : Any>(val k: K, val v: V) {
fun getKey(): K {
return k
}
fun getValue(): V {
return v
}
}
// 星投影
val queryMap: QueryMap<*, *> = QueryMap("S", 1)
// CharSequence 类型
queryMap.getKey()
// Any 类型
queryMap.getValue()
逆变点的使用
逆变点星投影取下限,没有对下限的明确定义,所以invoke只能传入nothing,但是nothing并没有实例,所以并不能调用
class Funcation<in p1,in p2>{
fun invoke(p1: p1,p2: p2) = Unit
}
//调用
val f:Funcation<*,*> = Funcation<String,Number>()
f.invoke("ss",1)
比较适合作为描述类场景使用:如下
val queryMap: QueryMap<*, *>
if( is Function<*,*>){...}
HashMap<String,List<*>>()
四、泛型的实现原理与内敛特化
java与kotlin泛型实现原理简介
首先知道一个概念:java和kotlin实现泛型的机制是伪泛型,编译后实现类型擦除,进行类型了转换。
//编译前
fun <T:Comparable<T>> maxOf(a:T,b:T):T{
return if(a>b) a else b
}
//编译后
fun maxOf(a:Comparable,b:Comparable):Comparable{
return if(a>b) a else b
}
常见的泛型实现原理
伪泛型:编译时擦除类型,运行时无实际类型生成。列如:java、kotlin
真泛型:编译时生成真实类型,运行时也存在该类。列如:c#、c++
所以,对于java以及kotlin来说。泛型类型无法被当作真实类型。
所以,kotlin出现了 内敛特化reified
内敛特化reified
当泛型使用reified修饰过之后,发现泛型可以向下传递,以及获取到对应的java类了!
内敛特化的简单实例运用(简单定义一个Gson的扩展函数吧)
inline fun <reified T> Gson.fromJson(json: String): T = fromJson(json, T::class.java)
fun main() {
val gson = Gson()
//类型自动推导
val person:Person = gson.fromJson("""{...}""")
val am = gson.fromJson<Person>("""{...}""")
}
总结
以上,就是泛型相关了内容了。学习了这么多,下面写一个小demo吧。Demo做一个可灵活配置的通知基类,响应式编程(核心思想就是,通过泛型传递父类可获取到子类类型)。
首先我们定义一些通用的头文件
typealias OnConfirm = () -> Unit
typealias OnCancel = () -> Unit
private val EmptyFunction = {}
定义一个转换的接口
interface SelfType<Self> {
val self: Self
get() {
// 将当前的类型转入传入的泛型
return this as Self
}
}
写一个通知类
open class Notification(val title: String, val content: String)
open class ConfirmNotification(
title: String,
content: String,
val onConfirm: OnConfirm,
val onCancel: OnCancel
) : Notification(title, content)
写一个通知的构建类
open class NotificationBuilder<Self : NotificationBuilder<Self>> : SelfType<Self> {
// protected 只能私有或者继承类使用
protected var title = ""
protected var content = ""
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)
}
再写 ConfirmNotificationBuilder 这时候只要把 ConfirmNotificationBuilder 类型通过泛型传递过去 , NotificationBuilder title以及content返回的 self类型 就是ConfirmNotificationBuilder 了
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")
.content("helloYa")
.onConfirm{
print("confirm")
}.onCancel{
print("cancel")
}
.build()
.onConfirm.invoke()
}