本文原始发表于:https://juejin.cn/post/7079090729057779743
以下文章翻译自《Effective Kotlin: Best practices》 中的 Chapter 3 - Item24 -
Consider variance for generic types
更多关于泛型的内容可参见我的另一篇文章:《一文了解 Java/Kotlin 中的泛型》
条目 24:关注泛型的型变
名词解释表
英文 | 中文 | 解释 |
---|---|---|
type parameter | 类型参数 | 泛型中尖括号中的参数,例如 List<T> 中的 T ,Comparable<Int> 中的 Int 等 |
variance modifiers | 型变修饰符 | in 和 out |
- | 子类泛型 | 标准翻译应为:类型参数为子类的泛型,为了描述方便,此处简称为「子类泛型」 |
- | 父类泛型 | 标准翻译应为:类型参数为父类的泛型,为了描述方便,此处简称为「父类泛型」 |
function type | 函数类型 | 形如:(T)-> U |
译者注:本篇专有名字比较多,为了方便理解和记忆,在此列出名词对照表
假设我们有以下泛型类:
class Cup<T>
上述泛型类的类型参数 T
没有指定任何型变修饰符(in
或者 out
), 因此默认是不型变的。不型变意味着子类泛型和父类泛型之间没有任何继承关系,比如:Cup<Int>
和 Cup<Number>
、Cup<Any>
和 Cup<Noting>
之间没有任何继承关系。
fun main() {
val anys: Cup<Any> = Cup<Int>() // 编译错误,类型不匹配
val nothings: Cup<Nothing> = Cup<Int>() // 编译错误
}
如果我们想要让他们有继承关系,我们就需要使用型变修饰符:out
和 in
,其中 out
使得泛型协变,而 in
使得泛型逆变:
class Cup<out T>
open class Dog
class Puppy: Dog()
fun main(args: Array<String>) {
val b: Cup<Dog> = Cup<Puppy>() // 协变之后,子类泛型是父类泛型的子类,子类可以赋值给父类
}
class Cup