1 Java 和 Kotlin 中的泛型
1.1 型变
先看部分代码
Kotlin:
var mutableListOf1 = mutableListOf<Any>()
mutableListOf1.add(1)
mutableListOf1.add("234")
println(mutableListOf1[1])
Java:
List list = new ArrayList();
list.add(1);
list.add("234);
println(list.get(1)) //报错 类抓换异常 CastException
如果熟悉Java的泛型,可以知道,Java在编译是泛型擦除的,所以在没有声明泛型类型时,List就是List<Object>
类型,可以往里放任何类型的数据;但是在取出数据的时候,就报错,这就说明,List<String>
并不是List<Object>
的子类,Java的泛型不是型变的。
但是Kotlin就不会存在这个问题,即便是Any类型的集合,在取数据时依然可以取出没有报错,这就是型变
1.2 协变
那Java中的泛型不是型变的,我要怎么才能正确地取出数据呢?一种就是声明确切的泛型,例如List<String>
,只能传入String类型,取出的也是String类型;还有一种方式就是通配符
List<? extends UserInfo> list = new ArrayList<Student>();
list集合声明了通配符泛型 ? extends A ,这就是定义了上限的协变,只能从中取出数据,但是不能存数据,取出数据是UserInfo,是安全的;
Kotlin中定义的协变是通过out关键字,out关键字修饰的泛型,只能出现在返回值,不能作为输入值消费,只可取
interface clsA<out T>{
fun get() : T
}
1.3 逆变
与协变相反的是,在Java中,使用super关键字 ? super A 定义了下限的逆变,此种方式只能存储数据,不能取出数据,因为不知道其中存储的是super的哪个父类,存储安全
与Java对应的,Kotlin中是通过in 关键字修饰协变泛型,通过in修饰的只能在输入值,不能作为返回值,也是存储安全的