简单泛型
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) //不会报错。
由上述代码可以看出,
? extends T是可取不可存的——入参中只要出现T类型的函数,都不可被访问。? 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); //在存值时不会有影响。
- 由上述代码可以看出,
? super T是可存不可取——返回值中是T类型的函数,都不可被访问。
PECS原则:
- 频繁往外读取内容的,适合用上界Extends。
- 经常往里插入的,适合用下界Super
kotlin中使用 in 、 out、*表示 通配符边界
当我们表示一个受限制的类型时,我们称它为类型投影, 它只能用于对类与接口的声明。所谓投影,可以理解是实际类型对泛型类型的映射, 而严格的限制带来了带来安全性:
-
in T代表只支持入参,T类型作为类型的下界,例:
Array<in String>对应于 Java 的Array<? super String>可以接受CharSequence类型或者Object类型 out T代表只支持出参,T类型作为类型的上界
例:Array<out Number>对应于 Java 的Array<? extends Number>可以接受Integer类型或者Double类型 。
当我们不希望对出参、入参进行限制,只希望所有具体的实例化都是该泛型的子类。(还记得ArrayList<String> 不是ArrayList<Object>的子类吗),Kotlin提供了*投影解决此问题
-
*投影可以不受类型的限制,对于<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"
}