Kotlin开荒小队——从Java到Kotlin

泛型、型变与投影

2018-01-04  本文已影响29人  doulala

简单泛型

kotlin 对于简单泛型的支持与java类似, 可以通过通配符,提升代码的灵活度

data class Response<T>(val code: Int, var body: T) { }/定义了一个泛型类

限定型泛型

在编码实践中,通常来说只使用简单的通配符来增加自由度,我们也需要用到限定性泛型,可以通过where关键字来约束自由度

interface callback<in T> 
       where T : Response<Any> { //T 必须是Response类型
   fun onSuccess(response: T)
   fun onFailed()
}

泛型的通配符边界

先说明一个java 中泛型的通配符边界的预备知识:

1 . ? extends T叫做上界通配符,用来表示所有T类型及其子类型。例如List<? extends Number>List<Integer>的超类。

ArrayList<? extends Number> list=new ArrayList<Integer>(); //  ? extends Number :可以接收所有Number的子类

list.add(Integer(1));  //会报错,因为编译器并无法了解该超类(? extends Number)泛型的实现类(Integer)的类型。

Number number=list.get(0) //不会报错。
  1. 由上述代码可以看出, ? extends T是可取不可存的——入参中只要出现T类型的函数,都不可被访问。

  2. ? super T叫做下界通配符,用阿里表示所有T类型及其超类。例如List<? super Number>List<Object>的超类,

ArrayList<? super Integer> list=new ArrayList<Object>();
Object a= list.get(0)  //? super 在取值时只能是Object
list.add(1); //在存值时不会有影响。
  1. 由上述代码可以看出, ? super T是可存不可取——返回值中是T类型的函数,都不可被访问。
PECS原则:
  - 频繁往外读取内容的,适合用上界Extends。
  - 经常往里插入的,适合用下界Super

kotlin中使用 inout*表示 通配符边界

当我们表示一个受限制的类型时,我们称它为类型投影, 它只能用于对类与接口的声明。所谓投影,可以理解是实际类型对泛型类型的映射, 而严格的限制带来了带来安全性:

  1. in T 代表只支持入参,T类型作为类型的下界,

    Array<in String>对应于 Java 的 Array<? super String>可以接受 CharSequence 类型或者 Object 类型

  2. out T 代表只支持出参,T类型作为类型的上界
    Array<out Number>对应于 Java 的 Array<? extends Number>可以接受 Integer 类型或者 Double 类型 。

当我们不希望对出参、入参进行限制,只希望所有具体的实例化都是该泛型的子类。(还记得ArrayList<String> 不是ArrayList<Object>的子类吗),Kotlin提供了*投影解决此问题

  1. *投影 可以不受类型的限制,对于<out T>来说,*投影 相当于<out Any>; 而对于<in T>来说,*投影相当于<in Nothing>

    // TODO

简单泛型的扩展

kotlin支持针对泛型的扩展,比如给每个Logger添加一个code解析方法:

interface logger {
    fun log(tag: String, value: String)
}

class MyLogger : logger {
    override fun log(tag: String, value: String) {
        System.out.println("$tag  do $value")  
    }
}

fun <T> T.write(text: String): Unit where  T : logger { //针对所有logger添加扩展
    this.log("test", "write $text") 
}

fun main(args: Array<String>) {
    var log: MyLogger = MyLogger()
    log.write("doulala") //print  "test  do write doulala"
}
上一篇 下一篇

猜你喜欢

热点阅读