天天看点

Android Kotlin(四) 泛型1. 泛型2. 泛型函数3. 泛型约束4 . 类型变异5. 类型投射

首先申明下,本文为笔者学习《Kotlin 程序开发入门精要》的笔记,并加入笔者自己的理解和归纳总结。

1. 泛型

所谓泛型,就是指在定义数据结构时,只指定类型的占位符,待到使用该数据结构时再指定具体的数据类型。

定义泛型类型变量,可以完整地写明类型参数,如果编译器可以自动推定类型参数,也可以省略类型参数。

class Data<T>(v: T) {
    var value = v
}

fun main(args: Array<String>) {
    // 创建类的实例时指定类型参数
    var strData: Data<String> = Data("Hello World")
    // 编译器会进行类型推断
    var intData = Data(12)

    println(strData.value)  // Hello World
    println(intData.value)  // 12
}
           

2. 泛型函数

泛型函数的类型参数要放在函数名的前面。

fun <T> copy(d: Data<T>): Data<T> {
    return Data(d.value)
}
           

3. 泛型约束

泛型约束常见的是上界约束,类似于Java的

extends

关键字,在冒号

(:)

后面指定的类型就是泛型参数的上界。如果没有指定,则默认使用的上界类型是

Any?

fun <T : Comparable<T>> equals(v1: T, v2: T): Boolean {
    return v1.compareTo(v2) == 0
}

fun main(args: Array<String>) {
    println(equals(1, 1))  // true
    println(equals(1, 2))  // false
}
           

在定义泛型的尖括号

<>

内,只允许定义唯一一个上界,如果需要指定多个上界,使用单独的

where

子句。

interface ICopy<T> {
    fun copy(): T
}

fun <T> copy(t: T) : T
      where T : Comparable<T>, T : ICopy<T> {
    return t.copy()
}
           

4 . 类型变异

kotlin泛型没有提供通配符,取而代之的是

out

in

关键字。

out

声明的泛型占位符只能在获取泛型类型值的地方,如函数的返回值。

class OutData<out T>(val v: T) {

    fun getValue(): T {
        return v
    }
}

fun main(args: Array<String>) {
    var strData = OutData<String>("Hello World")
    var objData: OutData<Any> = OutData("Object")

    objData = strData  // OutData<String>可以看做OutData<Any>的子类
}
           

in

声明的泛型占位符只能在设置泛型值的地方,如函数的参数。

class InData<in T>() {

    fun setValue(t: T) {
    }
}

fun main(args: Array<String>) {
    var intData = InData<Int>()
    var anyData = InData<Any>()

    intData = anyData  // InData<Any>可以看做InData<Int>的子类
}
           

5. 类型投射

A

是类

B

的父类,但

Array<A>

Array<B>

不是继承关系,

out

in

关键字可以对类型投射。

open class A{}
class B : A() {}

fun copy(from: Array<out A>, to: Array<A>) {
}

fun fill(dest: Array<in B>, v: B) {	
}

fun main(args: Array<String>) {
    var aArr: Array<A> = arrayOf(A(), A())
    var bArr: Array<B> = arrayOf(B(), B())

    copy(bArr, aArr)
    fill(aArr, B())
}
           
  • Kotlin 中的

    out A

    类似于 Java 中的

    ? extends A

    ,即泛型参数类型必须是A或者A的子类,用来确定类型的

    上限

  • Kotlin 中的

    in B

    类似于 Java 中的

    ? super B

    ,即泛型参数类型必须是B或者B的父类,用来确定类型的

    下限

当我们不知道泛型参数的类型信息时,但仍需要安全的使用它时,可以使用星投影,用星号

*

表示。如果类型定义为

interface Function<in T, out U>

,那么可以出现以下几种信号投射。

Function<*, String>,代表Function<in Nothing, String>
Function<Int, *>,代表Function<Int, Out Any?>
Function<*, *>,代表Function<in Nothing, Out Any?>
           

源码下载: https://github.com/nai-chen/KotlinBlog

继续阅读