阅读本文你将了解:
- 什么是型变、协变、逆变和不型变
- 在 Java 和 Kotlin 中如何实现以上型变
- Java 和 Kotlin 中泛型的异同
在 Java/Kotlin 中,子类对象是可以赋值给一个父类类型的,但是父类对象不可以赋值给子类类型,例如:
代码语言:text复制// Dog 是 Animal 的子类
class Animal {}
class Dog: Animal() {}
val animal: Animal = dog // 把子类对象赋值给一个父类类型是可以的,dog 也是一种 Animal
val dog: Dog = animal // 把父类对象赋值给一个子类类型是不可以的,不是所有 animal 都是 dog
在引入泛型之后,情况变得更复杂:类型参数为子类的泛型类型不是类型参数为父类的泛型类型的子类,听起来很绕,看代码:
代码语言:text复制// dogs 不是 animals 的子类
val dogs: List<Dog>
val animals: List<Animal>
// dogs 和 animals 不具备任何继承关系,因此以下代码会编译报错
val animals: List<Animal> = dogs
类型参数: 泛型中尖括号中的参数称为类型参数,比如
List<String>
中的String
就是类型参数,和普通参数不同,类型参数传递的是一个类型而不是对象
为了描述方便,以下把所有「类型参数为子类的泛型」简称为「子类泛型」,「类型参数为父类的泛型」简称为「父类泛型」
对于从 Java 转到 Kotlin 的开发者们来说,要了解泛型,最好先搞懂 Java 中的泛型,再来看 Kotlin 的泛型时会变得易如反掌。
Java 中的泛型
泛型的型变(variance)
- 协变(Covariance):子类泛型是父类泛型的子类型,可以把子类泛型赋值给父类泛型
- 逆变(Contravariance):父类泛型(可以看作)是子类泛型的子类型,可以把父类泛型赋值给子类泛型
- 不型变(Invariant):子类泛型和父类泛型没有任何继关系,也不可以相互赋值