Kotlin学习笔记(九)【泛型】

Kotlin泛型

泛型,即 “参数化类型”,将类型参数化,可以用在类,接口,方法上。
与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。
声明一个泛型类:

class Box<T>(t: T) {
    var value = t
}

创建类的实例时我们需要指定类型参数:

val box: Box = Box(1)
// 或者
val box = Box(1) // 编译器会进行类型推断,1 类型 Int,所以编译器知道我们说的是 Box

以下实例向泛型类 Box 传入整型数据和字符串:

fun main(args: Array) {
    val boxInt: Box = Box(1)
    val boxString: Box = Box("qfxl")
    println(boxInt.value)
    println(boxString.value)
}

class Box(t: T) {
    var value = t
}

输出结果为:
1
qfxl

定义泛型类型变量,可以完整地写明类型参数,如果编译器可以自动推定类型参数,也可以省略类型参数。
Kotlin 泛型函数的声明与 Java 相同,类型参数要放在函数名的前面:

fun main(args: Array) {
    val boxInt = boxIn(1)
    val boxString = boxIn("qfxl") //自动推断为String
    println(boxInt.value)
    println(boxString.value)
}

class Box<T>(t: T) {
    var value = t
}

fun  boxIn(t: T) = Box(t)

输出结果为:
1
qfxl

在调用泛型函数时,如果可以推断出类型参数,可以省略泛型参数。
以下实例创建了泛型函数 doPrint,函数根据传入的不同类型做相应处理:

fun main(args: Array) {
    val name = "qfxl"
    val age = 26
    val bo = false

    doPrint(name)
    doPrint(age)
    doPrint(bo)
}

fun  doPrint(t: T) {
    when (t) {
        is String -> println("T is String upperCase is ${t.toUpperCase()}")
        is Int -> println("T is Int value is $t")
        else -> println("T is not String or Int")
    }
}

输出结果为:

T is String upperCase is QFXL
T is Int value is 26
T is not String or Int

泛型约束

我们可以使用泛型约束来设定一个给定参数允许使用的类型。
Kotlin 中使用 : 对泛型的的类型上限进行约束。
最常见的约束是上界(upper bound):

fun > sort(list: List) {
    // ……
}

Comparable 的子类型可以替代 T。 例如:

sort(listOf(1, 2, 3)) // OK。Int 是 Comparable 的子类型
sort(listOf(HashMap())) // 错误:HashMap 不是 Comparable> 的子类型

默认的上界是 Any?。
对于多个上界约束条件,可以用 where 子句:

fun <T> cloneWhenGreater(list: List<T>, threshold: T): List<T>
    where T : Comparable, Cloneable {
      return list.filter(it > threshold).map(it.clone())
    }

型变

Kotlin 中没有通配符类型,它有两个其他的东西:声明处型变(declaration-site variance)与类型投影(type projections)。

声明处的类型变异使用协变注解修饰符:in、out,消费者 in, 生产者 out。

协变(covariant:Foo<父类> = Foo<子类>)

协变为父类泛型型变为具体子类,Kotlin 提供 in 关键字,来代替 Java 中 的通配符语法,同时为了解决Java中泛型型变类型擦除中,所引起的类型转换安全,Kotlin 采用了 C# 的策略,即协变类型作为消费者,只能读取而不能写入;

使用 out 使得一个类型参数协变,协变类型参数只能用作输出,可以作为返回值类型但是无法作为入参的类型:

// 定义一个支持协变的类
class Runoob(val a: A) {
    fun foo(): A {
        return a
    }
}

fun main(args: Array<String>) {
    var strCo: Runoob<String> = Runoob("a")
    var anyCo: Runoob = Runoob("b")
    anyCo = strCo
    println(anyCo.foo())   // 输出 a
}

**逆变(contravariance:Foo<子类> = Foo<父类>)
逆变为子类型型变为具体父类,Kotlin 提供 out 关键字,来代替 Java 中

你可能感兴趣的:(Android,Kotlin,Kotlin)