Kotlin:声明处协变 ,在类型参数声明处提供
Java:使用处协变,具体使用的时候才声明协变
我们随便定义一个泛型如下:
class B<T extends CharSequence>{
}
这个表示在实例化B的时候你提供的泛型T必须是CharSequence或者CharSequence的子类,这个和Java的使用处协变不是一回
事。我们说的使用处协变是下面这种形式
B<? extends ...>
两种方式不要混为一谈。
举个协变例子:
interface Producer<out T> {
fun product(): T
}
T前面有out修饰,表示T是一个协变类型。如果泛型T是协变类型,那么只能用于一个方法的返回类型。也就是说如果一个类里面的泛型是协变类型,只能用于一个方法的返回类型。
可以看到product()方法的返回类型是T类型。这个T是不能作为输入类型(参数)的。
可以这么记produce = output = out 生产者
举个协变例子:
interface Consumer<in T> {
fun consume(item: T)
}
如果泛型类只是将泛型类型作为其方法的输入类型(参数),那么我们就可以使用in。
可以这么记consumer = input = in
还有一种是不变类型,上例子
interface ProducerCoonsumer<T> {
fun produce(): T
fun consume(item: T)
}
如果泛型同时将泛型类型作为其方法的输入类型与输出类型,那么我们就不能使用out与in来修饰泛型
再来个协变的例子
open class Fruit
open class Apple :Fruit()
class ApplePear :Apple()
interface Producer<out T> {
fun product(): T
}
class FruitProducer : Producer<Fruit> {
override fun product(): Fruit {
println("Produce Fruit")
return Fruit()
}
}
class AppleProducer :Producer<Apple>{
override fun product(): Apple {
println("produce Apple")
return Apple()
}
}
class ApplePearProducer :Producer<ApplePear>{
override fun product(): ApplePear {
println("produce ApplePear")
return ApplePear()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main7)
val producer1: Producer<Fruit> = FruitProducer()
val producer2: Producer<Fruit> = AppleProducer()
val producer3: Producer<Fruit> = ApplePearProducer()
}
对于out泛型来说,我们可以将子类型对象赋给父类型引用
看看逆变的例子
class Human : Consumer<Fruit> {
override fun consume(item: Fruit) {
println("consume Fruit")
}
}
class Man :Consumer<Apple>{
override fun consume(item: Apple) {
println("consume Apple")
}
}
class Boy :Consumer<ApplePear>{
override fun consume(item: ApplePear) {
println("consume ApplePear")
}
}
interface Consumer<in T> {
fun consume(item: T)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main8)
val consumer1: Consumer<ApplePear> = Human()
val consumer2: Consumer<ApplePear> = Man()
val consumer3: Consumer<ApplePear> = Boy()
}
}
对于in泛型来说,我们可以将父类型对象赋给子类型引用