DEVLOG 9.25 Kotlin泛型
Java中的泛型
Java中的泛型是不形变的,List<String> 并不是List<Object>的子类型。这样做的一个好处是避免因为类型产生的异常(数组是形变的):
PECS: producer extends, consumer super
? extends E 表示此方法接受E和E的子类型。可以读(producer)不可以写。因为已知是E的子类型,可以使用E承接(上转型)
? super E 表示此方法接受E和E的父类型,可以写不可以读 ???
Kotlin中的泛型
1. 泛型介绍
可以通过where指定类型参数T的范围
2. 类型擦除
谈到Java的类型擦除要说明两个重点:
Java的List是不变的,数组是协变的。
Java的数组在运行时可以获取自身的类型,但是List不行:
Kotlin中的泛型机制和Java中的相同。Java和Kotlin中的泛型在编译之前会检查类型是否存在问题,但是在编译之后通过强制类型转换等方式保证泛型特性。
如何在运行时获取类型信息?
这种方式不能支持带有类型参数的类获取class对象。
使用匿名内部类,匿名内部类在初始化阶段你就会绑定父类或者父接口的相应信息:
使用Kotlin的特性打破类型不变!
在Java中下面的代码是行不通的:
在Kotlin中以下的代码是可以运行的:
这里需要说明一点,在Kotlin中的List和Java中的List定义不同:
比Java中多了out,(但是ArrayList是相同的)。也就是说Kotlin中的ArrayList<String>(List<String>)是List<Any>的子类型。
支持协变的List和它要付出的代价
如果支持协变的话会使得List存在安全问题。因为List<String>是List<Any>的子类型,然后往里面存储内容的时候可以放任何Any的子类。所以在Kotlin中,List并不能存储内容:

也就是说支持协变的List不能将类型参数作为方法参数
支持逆变的Comparator
Comparator需要支持逆变。

但是支持逆变的泛型类型参数不能作为方法的类型参数。考虑上面的情况,List<in T>可能会存入一个T的父类,向下转型是不安全的。但是逆变不影响泛型参数作为方法的返回值。

所以总的来说和Java中类似,out支持协变,可以当做producer;in支持逆变,可以当做consumer。
可以这样记:in->输入-> 方法参数 out->输出->返回值