泛型、型变与投影

作者: doulala | 来源:发表于2018-01-04 09:01 被阅读29次

简单泛型

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"
}

相关文章

  • 泛型、型变与投影

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

  • 泛型编程中的型变

    在泛型编程中,经常会提到型变。型变分为两种:协变与逆变。协变covariant表示与泛型参数T的变化相同,而逆变c...

  • Kotlin学习笔记 - 泛型

    1. 基本用法 2. 型变 型变包括 协变、逆变、不变 三种: 协变:泛型类型与实参的继承关系相同 逆变:泛型类型...

  • Kotlin泛型的高级特性(六)

    泛型的高级特性1、泛型实化2、泛型协变3、泛型逆变 泛型实化 在Java中(JDK1.5之后),泛型功能是通过泛型...

  • Kotlin中的协变、逆变和不变

    共1083字,阅读需要2分钟 泛型实参的继承关系对泛型类型的影响 协变:泛型类型与实参的继承关系相同 逆变:泛型类...

  • Objective-C 泛型 协变 逆变

    为什么要使用泛型 如何使用泛型 限制泛型 协变 逆变 为什么要使用泛型 在使用NSArray, NSSet, NS...

  • Java 泛型

    泛型类 例如 泛型接口 例如 泛型通配符 泛型方法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型上下边...

  • Scala 泛型协变与泛型边界

    代码准备 泛型协变 泛型协变、逆变、不变是指拥有泛型的类在声明和赋值时的对应关系。 协变:声明时泛型是父类,赋值时...

  • Java 泛型与通配符

    参考地址:《Java 泛型,你了解类型擦除吗?》 《Java中的逆变与协变》 《java 泛型中 T、E .....

  • 泛型的使用

    泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法 泛型类 泛型接口 泛型通配符 泛型方法 静态方法与...

网友评论

    本文标题:泛型、型变与投影

    本文链接:https://www.haomeiwen.com/subject/mdfagxtx.html