Kotlin学习(六):kotlin泛型

12 篇文章 0 订阅

系列文章路引 👀 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()
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pumpkin的玄学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值