一文了解 Java/Kotlin 中的泛型

2022-06-29 22:02:33 浏览数 (1)

阅读本文你将了解:

  • 什么是型变、协变、逆变和不型变
  • 在 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):子类泛型和父类泛型没有任何继关系,也不可以相互赋值

0 人点赞