Kotlin泛型的理解

和Java的泛型相比,Koltin的泛型还是与之不同的。直达链接Java的泛型理解

泛型约束

/**
 * 并不是所有的类型参数T都具有可比性,必须限定T的类型,如果只是数字类型比较可以限定Number,
 * 因为Int,Double等数字类型都继承Number,是Number的子类型。声明类型参数时在T后面添加冒号:和限定类型,这种表示方式就是泛型约束。
 * 泛型约束主要用于泛型函数和泛型类的声明。
 */
private fun <T: Number> isEqual(a: T,b: T): Boolean{
    return (a == b)
}
 
/**
 * 为此可以将类型参数限定为Comparable<T>接口类型,所有可以比较的对象都实现Comparable<T>接口,Comparable<T>本身也是泛型类型。
 */

fun <T : Comparable<T>> isEqua(a: T,b: T): Boolean{
    return (a == b)
}

out(协变)

如果泛型类只将泛型类型作为函数的返回(输出),那么使用 out:

interface Production<out T> {
    fun produce(): T
}

in(逆变)

如果泛型类只将泛型类型作为函数的入参(输入),那么使用 in:

interface Consumer<in T> {
    fun consume(item: T)
}

invariant(不变)

如果泛型类既将泛型类型作为函数参数,又将泛型类型作为函数的输出,那么既不用 out 也不用 in:

interface ProductionConsumer<T> {
    fun produce(): T
    fun consume(item: T)
}

  • out 声明我们称之为协变,就是可以兼容自己及其子类,相当于 Java 的 ? extend E
  • in 声明我们称之为逆协变,就是可以兼容自己及其父类,相当于 Java 的 ? super E

为什么不直接用 Java 的声明方式?因为 Java ? extends E 和 ? super E 只能用于方法,而 in 和 out 是可以用于类和方法的

  • 子类泛型对象可以赋值给父类泛型对象,用 out。
  • 父类泛型对象可以赋值给子类泛型对象,用 in;
    在这里插入图片描述

星号投影

  • 星号投影用来表明“不知道关于泛型实参的任何信息”。
  • 类似于 Java 中的无界类型通配符?, Kotlin 使用星号投影*。
  • *代指了所有类型,相当于Any?
    例如:MutableList<*> 表示的是 MutableList<out Any?>
fun main() {
    val list1 = mutableListOf<String>()
    list1.add("string1")
    list1.add("string2")
    printList(list1)

    val list2 = mutableListOf<Int>()
    list2.add(123)
    list2.add(456)
    printList(list2)
}

fun printList(list: MutableList<*>) {

    println(list[0])
}

正是由于使用 out 修饰以及星号投影的类型不确定性,会导致写入的任何值都有可能跟原有的类型冲突。因此,星号投影不能写入只能读取

发布了63 篇原创文章 · 获赞 1 · 访问量 2101

猜你喜欢

转载自blog.csdn.net/weixin_42046829/article/details/105409784