从Java说起 kotlin 的协变与逆变
原创从Java说起:Kotlin的协变与逆变
在Java编程语言中,泛型的引入为类型保险提供了强势的保障,但它也有自己的局限性。其中一个局限就是类型通配符的纷乱性,特别是在涉及类型边界时。Kotlin作为Java的姊妹语言,在Java泛型在出现的同时进行了改进,引入了协变(covariance)与逆变(contravariance)的概念,让泛型的使用更为灵活和便捷。
Java中的泛型局限性
在Java中,泛型类型参数是不变的(invariant),这意味着List
// Java代码
List
apples = new ArrayList<>(); List
fruits = apples; // 编译不正确,类型不匹配
以上代码无法通过编译,由于Java的泛型不拥护下界类型转换。为了解决这个问题,Java引入了通配符?
Kotlin的协变
Kotlin通过out关键字提供了协变拥护,允许将一个泛型类型的子类对象赋值给父类的泛型对象。
// Kotlin代码
open class Fruit
class Apple : Fruit()
fun main() {
val apples: List
= listOf () val fruits: List
= apples // 这是允许的,由于List 是协变的 }
在Kotlin中,List
描述这个列表只能生产(produce)Apple或者其子类型的对象,但不能接受Apple的父类型对象。这里的out
关键字描述了泛型类型的输出位置,即生产者(Producer)。
Kotlin的逆变
Kotlin同样提供了逆变的拥护,通过使用关键字in
。逆变允许将一个泛型类型的父类对象赋值给子类的泛型对象。
// Kotlin代码
fun main() {
val fruits: List
= listOf () val apples: List
= fruits // 这是允许的,由于List 是逆变的 }
在这里,List
描述这个列表可以接受(consume)Fruit或者其子类型的对象,但不能生产除了Fruit以外的对象。逆变类型首要用于函数参数的类型。
总结
Kotlin的协变与逆变通过关键字out
和in
简化了泛型的使用,让类型转换更加灵活,同时保持了类型保险。这些特性让Kotlin的泛型更加易于领会和使用,降低了在Java中由于泛型让的纷乱通配符的使用。