面试题答案
一键面试协变(out)
- 语法:在泛型声明时,在类型参数前加上
out
关键字。例如:
interface Producer<out T> {
fun produce(): T
}
- 作用:协变允许将
Producer<子类型>
赋值给Producer<父类型>
,即类型参数是“只读”的。这样做确保了不会通过Producer
接口去修改T
类型的值,只用于读取操作。 - 实际开发场景应用 - 集合操作:
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)
- 语法:在泛型声明时,在类型参数前加上
in
关键字。例如:
interface Consumer<in T> {
fun consume(item: T)
}
- 作用:逆变允许将
Consumer<父类型>
赋值给Consumer<子类型>
,即类型参数是“只写”的。这样做确保了只能传入父类型或其子类型的值,用于写入操作。 - 实际开发场景应用 - 函数参数传递:
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>
。