当咱们在 Kotlin 中定义泛型时,咱们会发现它须要使用到 in
和 out
两个关键字来定义。从形式上来说,这是一种定义「逆变」和「协变」的方式。ide
那啥叫逆变?啥叫协变?能够参考下维基百科的定义:协变与逆变函数
out(协变)spa
若是泛型类只将泛型类型做为函数的返回(输出),那么使用 out:code
interface Production<out T> {
fun produce(): T
}
复制代码
能够称之为生产类/接口,由于它主要是用来生产(produce)指定的泛型对象。所以,咱们能够简单地这样记忆:对象
produce = output = out接口
in(逆变)ip
若是泛型类只将泛型类型做为函数的入参(输入),那么使用 in:get
interface Consumer<in T> {
fun consume(item: T)
}
复制代码
能够称之为消费者类/接口,由于它主要是用来消费(consume)指定的泛型对象。所以咱们能够简单地这样记忆:input
consume = input = instring
invariant(不变)
若是泛型类既将泛型类型做为函数参数,又将泛型类型做为函数的输出,那么既不用 out 也不用 in:
interface ProductionConsumer<T> {
fun produce(): T
fun consume(item: T)
}
复制代码
举个例子,咱们定义下汉堡类对象,它是一种快餐,也是一种食物。
open class Food
open class FastFood : Food()
class Burger : FastFood()
复制代码
根据上面定义的生产(Production)接口,咱们能够进一步扩展它们来生产食物、快餐和汉堡:
class FoodStore : Production<Food> {
override fun produce(): Food {
println("Produce food")
return Food()
}
}
class FastFoodStore : Production<FastFood> {
override fun produce(): FastFood {
println("Produce fast food")
return FastFood()
}
}
class InOutBurger : Production<Burger> {
override fun produce(): Burger {
println("Produce burger")
return Burger()
}
}
复制代码
如今,咱们能够这样赋值:
val production1 : Production<Food> = FoodStore()
val production2 : Production<Food> = FastFoodStore()
val production3 : Production<Food> = InOutBurger()
复制代码
显然,汉堡商店属于快餐商店,也属于食物商店。
所以,对于 out 类型,咱们可以将使用子类泛型的对象赋值给使用父类泛型的对象。
若是咱们修改以下,那么就会出错了,由于食物或快餐商店是能够生产汉堡,但不必定仅仅生产汉堡:
val production1 : Production<Burger> = FoodStore() // Error
val production2 : Production<Burger> = FastFoodStore() // Error
val production3 : Production<Burger> = InOutBurger()
复制代码
根据上面定义的消费(Consumer)接口,咱们能够进一步扩展它们来消费食物、快餐和汉堡:
class Everybody : Consumer<Food> {
override fun consume(item: Food) {
println("Eat food")
}
}
class ModernPeople : Consumer<FastFood> {
override fun consume(item: FastFood) {
println("Eat fast food")
}
}
class American : Consumer<Burger> {
override fun consume(item: Burger) {
println("Eat burger")
}
}
复制代码
咱们能够将人类、现代人、美国人指定为汉堡消费者,因此能够这样赋值:
val consumer1 : Consumer<Burger> = Everybody()
val consumer2 : Consumer<Burger> = ModernPeople()
val consumer3 : Consumer<Burger> = American()
复制代码
不难理解,汉堡的消费者能够是美国人,也能够是现代人,更能够是人类。
所以,对于 in 泛型,咱们可以将使用父类泛型的对象赋值给使用子类泛型的对象。
反之,若是咱们修改以下,就会出现错误,由于汉堡的消费者不单单是美国人或现代人。
val consumer1 : Consumer<Food> = Everybody()
val consumer2 : Consumer<Food> = ModernPeople() // Error
val consumer3 : Consumer<Food> = American() // Error
复制代码
参考资料: