kotlin从入门到看开 ₇


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


泛型

什么是泛型?

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

如何为函数声明泛型

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

如何为类声明泛型

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

泛型约束

  • >

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

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

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

泛型的实现机制

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

Kotlin对于真泛型的部分实现

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

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

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

输出结果

class java.lang.Integer

型变

协变(out)

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

逆变(in)

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

        /**
         * 我们看下实现,Comparable 
         * 逆变(in) :泛型类型与实参的继承关系相反
         * 这就可以解释通了
         */
        public interface Comparable {
            public operator fun compareTo(other: T): Int
        }

注意事项

  • 协变点

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

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

  • 逆变点

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

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

  • 不变点

    • T
    • 类型是可读写的
  • 型变点违规

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

星投影

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

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

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

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

你可能感兴趣的:(kotlin从入门到看开 ₇)