Android 协变和逆变
- Dog 是 Animal 的子类
- 型变分为:Invariant 抗变(不变)、Covariance 协变和 Contravariance 逆变
- 抗变:
List<Dog>
和List<Animal>
没有任何继承关系,直接赋值会编译报错,所以抗变严重制约了程序的灵活性 - 协变:
List<Dog>
是List<Animal>
的子类型,即子类型可以赋值给父类型 - 逆变:
List<Animal>
是List<Dog>
的子类型,即父类型可以赋值给子类型
协变
- 适用于 Producer 生产者角色的泛型类或接口,只能读取数据,不能写入
- 类中不能有接受该类型参数作为方法参数的成员,只能返回该类型
- Java 的
List<? extends Animal>
对应 Kotlin 的List<out Animal>
java
public void getOutAnimal(List<? extends Animal> list) {
for (Animal animal : list) {
//读取数据
}
}
kotlin
//Producer<String> 可以赋值给 Producer<Any>
interface Producer<out T> {
fun produce(): T //只能返回 T,不能接受 T 作为参数
}
逆变
- 适用于 Consumer 消费者角色的泛型类或接口,只能写入数据,不能读取
- 类中不能有返回该类型参数的成员,只能接受该类型作为参数
- Java 的
List<? super Dog>
对应 Kotlin 的List<in Dog>
java
public void putAnimalIn(List<? super Dog> list) {
//写入数据
list.add(new Dog()); //可以安全写入 Dog 或其子类
}
kotlin
//Consumer<String> 可以赋值给 Consumer<Any>
interface Consumer<in T> {
fun consume(value: T) //只能接受 T,不能返回 T
}
总结
- 协变:在 Java 中使用 ? extends E 表示,在 Kotlin 中使用 out E 表示,表示上界为 E
- 逆变:在 Java 中使用 ? super E 表示,而在 Kotlin 中使用 in E 表示,表示下界为 E
- PECS 原则:Producer-Extends,Consumer-Super
- Producer -> output -> out
- Consumer -> input -> in