Kotlin协变与逆变区别
在Kotlin中,协变和逆变是泛型编程中的两个重要概念,它们允许我们在类型系统中更加灵活地处理类型关系。
1.协变:协变允许我们使用比原始类型更具体的类型。在kotlin中,通过在类型参数上加out关键字来表示协变,生产者,例如,如果我们有一个泛型类List,其中T是一个协变类型参数,那么我们可以将List赋值给List,因为String是Any的子类型。
2.逆变:逆变允许我们使用比原始类型更一般的类型。在kotlin中,通过在类型参数上加in关键字来表示逆变,消费者,例如,如果我们有一个泛型函数fun foo(list: List),其中T是一个逆变类型参数,那么我们可以将List传递给foo函数,因为Any是String的超类型。
协变代码举例:
interface Producer<out T> {//协变 out 类似java中的 extend
fun produce(): T
}
open class Fruit
open class Apple: Fruit()
class FruitProducer:Producer<Fruit> {
override fun produce(): Fruit {
return Fruit()
}
}
class AppleProducer:Producer<Apple> {
override fun produce(): Apple {
return Apple()
}
}
fun <T> processProduce(producer:Producer<T>) {
val product = producer.produce()
println(product)
}
fun main(){
var fruitProducer:Producer<Fruit> = FruitProducer()
var appleProducer:Producer<Apple> = AppleProducer()
processProduce(fruitProducer)
processProduce(appleProducer)
// appleProducer = fruitProducer //报错,协变,不允许将Producer<Fruit>赋值给Producer<Apple>
// fruitProducer = appleProducer //协变,允许将Producer<Apple>赋值给Producer<Fruit>
}
逆变代码举例:
interface Consumer<in T>{ //逆变 in 类似java中的super
fun consume()
}
class FruitConsumer:Consumer<Fruit>{
override fun consume() {
println("consume fruit")
}
}
class AppleConsumer:Consumer<Apple>{
override fun consume() {
println("consume apple")
}
}
inline fun <T> processConsumer(consumer:Consumer<T>){
consumer.consume()
}
fun main() {
var fruitConsumer:Consumer<Fruit> = FruitConsumer()
var appleConsumer:Consumer<Apple> = AppleConsumer()
processConsumer(fruitConsumer)
processConsumer(appleConsumer)
// fruitConsumer = appleConsumer //报错,逆变,不允许将Consumer<Apple>赋值给Consumer<Fruit>
// appleConsumer = fruitConsumer //允许将Consumer<Fruit>赋值给Consumer<Apple>,
}