美文网首页
kotlin从入门到看开 ₇

kotlin从入门到看开 ₇

作者: 東方月初 | 来源:发表于2018-10-30 13:53 被阅读10次

    layout: post
    title: "kotlin-泛型"
    subtitle: "古人真厉害 不管他们实际想说的是什么 限制在一行最多7个字里面"


    泛型

    什么是泛型?

    • 泛化的类型或者说类型的抽象
    • 很多时候我们并不关心它是什么
    • 而关心它能做什么,这就是泛型要解决的问题.

    如何为函数声明泛型

    • 为函数声明泛型,泛型要放在函数名之前.
        fun < T : Comparable<T>> maxOf(a: T, b: T): T {
            return if (a > b) a else b
        }
    

    如何为类声明泛型

    • 为类声明泛型,泛型要放在类名之后
        class showText<T>(val i: T,  val j: T) {
            override fun toString(): String {
                return "$i,$j"
            }
    

    泛型约束

    • <T : Comparable<T>>

    • :冒号之后指定的类型是上界,泛型T只能是Comparable<T>的子类.

    • 若没有声明,默认的上界是Any? 在尖括号中只能指定一个上界.如果同一类型参数需要多个上界,我们需要一个单独的where子句

     fun<T> maxof(a:T,b:T):T
        where T:Comparable<T>,T:Cloneable {
            return if (a>b) a else b
        }
    

    泛型的实现机制

    • 何为真泛型(C#)
      • 真泛型编译前变异后,泛型都存在
    • 何为伪泛型(Java,Kotlin)
      • 伪泛型只存在编译之前,编译之后就随风而去了

    Kotlin对于真泛型的部分实现

    • 使用 inline(内联)关键字标记方法
    • 使用 Reifild(具体化)关键字标记泛型

    注意泛型具体化必须使用inline标记

       @Test
        fun addition_isCorrect() {
            Generic<Int>()
        }
        
        inline fun <reified T>Generic(){
            println(T::class.java)
        }
    

    输出结果

    class java.lang.Integer

    型变

    协变(out)

    • 泛型参数为协变时,这个类型的继承关系与泛型参数的继承关系是一致的.
    • kotlin中的协变(out)相当于java中的通配符 <?extends E>,表示接受 T 或者 T 的子类.
            /**
             * 协变
             * Number是Int的父类
             * List<Number>是List<Int>的父类
             */
            var list:List<Number> = listOf(1,2,3)
            val numlist:List<Number> = intList
    

    逆变(in)

    • 泛型参数为逆变时,这个类型的继承关系与泛型参数的继承关系是相反的.
    • kotlin中的逆变(in)相当于java中的通配符 <?super E>,表示接受 T 或者 T 的超类.
            /**
             * 逆变
             * Comparable<Int>居然是Comparable<Any>的父类我没有瞎吧?
             * 你没有瞎,可是为什么会这样呢?因为是逆变呀
             * Int的超类是Any
             */
            val intComparable : Comparable<Int> = object : Comparable<Any>{
                override fun compareTo(other: Any): Int {
                    return 0
                }
            }
    
            /**
             * 我们看下实现,Comparable<in T> 
             * 逆变(in) :泛型类型与实参的继承关系相反
             * 这就可以解释通了
             */
            public interface Comparable<in T> {
                public operator fun compareTo(other: T): Int
            }
    

    注意事项

    • 协变点

      • 一提到协变你就应该想到类型是只读的
      • 泛型参数:返回值类型

      对于谁只读呢? 对于泛型参数类型对应的变量时只读

    • 逆变点

      • 一提到逆变你就应该想到类型是只写的
      • 泛型参数:入参类型

      对于谁只写呢? 对于泛型参数类型对应的变量时只写

    • 不变点

      • <font size="3" color="#006666">T</font>
      • 类型是可读写的
    • 型变点违规

      • 使用 @UnsafeVariance 标注,让编译器闭嘴.

    星投影

    有时你对类型参数一无所知,但任然希望以安全的方式使用它.星投影就是你了.

            var list:List<*> = listOf(1,2,3)
    
    

    注意需要泛型实参时不能使用星投影

    //这样用可以吗当然不可以!!!!
        hello<*>()
        fun <T> hello() {}
    

    相关文章

      网友评论

          本文标题:kotlin从入门到看开 ₇

          本文链接:https://www.haomeiwen.com/subject/lwfgtqtx.html