reified解决的是什么问题?
泛型会在编译后类型擦除,在运行时无法获得泛型类型T的类型信息。
想要在运行时获取泛型类型信息,需要使用reified和inline配合。
Kotlin编译器会将reified方法内联(inline)到调用的地方(call-site)。
方法被内联到调用的地方后,泛型T会被替换成具体的类型。
所以 reified 使得泛型的方法假装在运行时能够获取泛型的类信息。
这样不用为了获取泛型的类型再单独给方法传一个Class参数。
协变是什么意思?
带 extends 限定(上界)的通配符类型使得类型是协变的(covariant)。
逆变是什么意思?
super限定的下界通配符使得类型是逆变的(contravariance)。
在 Java 中有 List<? super String>
是 List<Object>
、List<String>
的一个超类。
in和out关键字是做什么的?
使用关键字 out 来支持协变,等同于 Java 中的上界通配符 ? extends。
使用关键字 in 来支持逆变,等同于 Java 中的下界通配符 ? super。
上界通配符用于读取,是产出东西给外面用,所以是out。
下界通配符用于修改,是生产东西存到容器里,所以是in。
消费者 in, 生产者 out。
kotlin泛型中的where有什么作用?
Java 中声明类或接口的时候,可以使用 extends 来设置边界,将泛型类型参数限制为某个类型的子集:
1 | // T的类型必须是 Animal 的子类型 |
注意这个和前面讲的声明变量时的泛型类型声明是不同的东西,这里并没有 ?。
同时这个边界是可以设置多个,用 & 符号连接:
1 | // T 的类型必须同时是 Animal 和 Food 的子类型 |
Kotlin 只是把 extends 换成了 : 冒号。class Monster<T : Animal>
设置多个边界可以使用 where 关键字:class Monster<T> where T : Animal, T : Food
有人在看文档的时候觉得这个 where 是个新东西,其实虽然 Java 里没有 where ,但它并没有带来新功能,只是把一个老功能换了个新写法。
不过笔者觉得 Kotlin 里 where 这样的写法可读性更符合英文里的语法,尤其是如果 Monster 本身还有继承的时候:
1 | class Monster<T> : MonsterParent<T> |
实现一个 fill 函数,传入一个 Array 和一个对象,将对象填充到 Array 中,要求 Array 参数的泛型支持逆变(假设 Array size 为 1)
1 | fun <T> fill(to: Array<in T>, from: T) { |
实现一个 copy 函数,传入两个 Array 参数,将一个 Array 中的元素复制到另外个 Array 中,要求 Array 参数的泛型分别支持协变和逆变。
1 | fun <T> copy(from: Array<out T>, to: Array<in T>) { |