08-声明处型变
8.2.3 声明处型变
Kotlin相对于Java泛型较大的改动就是添加了声明处型变。在Java中,假设有一个泛型接口Source\
interface Source<T> {
T nextT();
}
虽然从语法上来说,将Source \
void demo(Source<String> strs) {
Source<Object> objects = strs; //编译错误,在Java中不允许
//…
}
为了解决这一问题,可以声明对象的类型为 Source<? extends Object>,但这样的操作显得毫无意义。在Kotlin中,有一种方法向编译器解释这种情况,即声明处型变。对于上面的代码,使用声明处型变可以进行如下修改。
abstract class Source<out T> {
abstract fun nextT(): T
}
fun demo(strs: Source<String>) {
val objects: Source<Any> = strs // 编译通过,因为T是一个out类型参数
//…
}
实际上,Kotlin存在大量的声明处型变,比如Iterable接口的声明。
public interface Iterable<out T> {
public operator fun iterator(): Iterator<T>
}
因为Collection接口和Map接口都继承自Iterable接口,而Iterable接口又被声明为生产者类型,所以所有的Collection对象和Map对象都可以实现安全的类型协变。代码如下。
val num:List<Number> = listOf(1,2,3)
在上面的表达式中,listOf()函数返回List\
除了out修饰的型变之外,Kotlin还提供了另外一种型变类型,即类型参数逆变,它使用关键字in修饰。声明的逆变只能被消费而不能被生产,逆变类的一个很好的例子是Comparable的实现。
abstract class Comparable<in T> {
abstract fun compareTo(other: T): Int
}
fun demo(x: Comparable<Number>) {
x.compareTo(1.0)
val y: Comparable<Double> = x // 编译通过
}