MST

星途 面试题库

面试题:Kotlin继承与多态中的协变逆变及实际应用

在Kotlin的继承与多态体系中,协变(out)和逆变(in)是如何体现的?请以自定义泛型类和接口为例,详细说明协变和逆变的语法、作用以及在实际开发场景(如集合操作、函数参数传递等)中的应用。
22.9万 热度难度
编程语言Kotlin

知识考点

AI 面试

面试题答案

一键面试

协变(out)

  1. 语法:在泛型声明时,在类型参数前加上 out 关键字。例如:
interface Producer<out T> {
    fun produce(): T
}
  1. 作用:协变允许将 Producer<子类型> 赋值给 Producer<父类型>,即类型参数是“只读”的。这样做确保了不会通过 Producer 接口去修改 T 类型的值,只用于读取操作。
  2. 实际开发场景应用 - 集合操作
fun printFruits(fruits: List<Fruit>) {
    fruits.forEach { println(it.name) }
}

class Fruit(val name: String)
class Apple : Fruit("Apple")

val apples: List<Apple> = listOf(Apple())
printFruits(apples)

这里 List 是协变的(List<out T>),所以 List<Apple> 可以赋值给 List<Fruit>

逆变(in)

  1. 语法:在泛型声明时,在类型参数前加上 in 关键字。例如:
interface Consumer<in T> {
    fun consume(item: T)
}
  1. 作用:逆变允许将 Consumer<父类型> 赋值给 Consumer<子类型>,即类型参数是“只写”的。这样做确保了只能传入父类型或其子类型的值,用于写入操作。
  2. 实际开发场景应用 - 函数参数传递
fun feedAnimal(animalFeeder: Consumer<Animal>) {
    val animal = Animal()
    animalFeeder.consume(animal)
}

class Animal
class Dog : Animal()

val dogFeeder: Consumer<Dog> = object : Consumer<Dog> {
    override fun consume(item: Dog) {
        println("Feeding a dog")
    }
}

feedAnimal(dogFeeder)

这里 Consumer 是逆变的(Consumer<in T>),所以 Consumer<Dog> 可以赋值给 Consumer<Animal>