# 深入理解 Kotlin 泛型
Kotlin 的泛型与 Java 一样,都是一种语法糖,即只在源代码中有泛型定义,到了 class 级别就被擦除了。 泛型(Generics)其实就是把类型参数化,真正的名字叫做类型参数,它的引入给强类型编程语言加入了更强的灵活性。
在这一节为大家继续带来 Kotlin 中的一些高级的内容:Kotlin 中的泛型。
# Why
- 架构开发的一把利器;
- 使我们的代码或开发出来的框架更加的通用;
- 增加程序的健壮性,避开运行时可能引发的 ClassCastException;
- 能够帮助你研究和理解别的框架;
- 自己造轮子需要,能用泛型解决问题;
在 Java 中,我们常见的泛型有:泛型类、泛型接口、泛型方法和泛型属性,Kotlin 泛型系统继承了 Java 泛型系统,同时添加了一些强化的地方。
# 目录
- 泛型接口 / 类(泛型类型)
- 泛型字段
- 泛型方法
- 泛型约束
- 泛型中的 out 与 in
# 泛型接口 / 类(泛型类型)
定义泛型类型,是在类型名之后、主构造函数之前用尖括号括起的大写字母类型参数指定:
# 泛型接口
| // 泛型接口 | |
| interface Drinks<T> { | |
| fun taste(): T | |
| fun price(t: T) | |
| } | 
# 泛型类
| abstract class Color<T>(var t: T/* 泛型字段 */) { | |
| abstract fun printColor() | |
| } | |
| class Blue { | |
| val color = "blue" | |
| } | |
| class BlueColor(t: Blue) : Color<Blue>(t) { | |
| override fun printColor() { | |
| println("color:${t.color}") | |
|     } | |
| } | 
# 泛型字段
定义泛型类型字段,可以完整地写明类型参数,如果编译器可以自动推定类型参数,也可以省略类型参数:
| abstract class Color<T>(var t: T/* 泛型字段 */) { | |
| abstract fun printColor() | |
| } | 
# 泛型方法
类型参数要放在方法名的前面:
| fun <T> fromJson(json: String, tClass: Class<T>): T? { | |
| val t: T? = tClass.newInstance() | |
|     return t | |
| } | 
# 泛型约束
限定泛型参数的类型
| // 泛型类型限定 - 1 | |
| // 所传递的类型 T 必须满足是 User 的子类 或 User 类 | |
| fun <T: User> fromJson(json: String, tClass: Class<T>): T? { | |
| ... | |
| } | |
| // 泛型类型限定 - 2 | |
| // 所传递的类型 T 必须同时满足 where 子句的所有条件,在下面的示例中,类型 T 必须既实现了 User, 也实现了 Comparable。 | |
| fun <T> fromJson(json: String, tClass: Class<T>): T? where T : User,T : Comparable<T> { | |
| ... | |
| } | 
# 泛型中的 out 与 in
在 Kotlin 中 out 代表协变,in 代表逆变,为了加深理解我们可以将 Kotlin 的协变看成 Java 的上界通配符,将逆变看成 Java 的下界通配符:
# out 约束泛型参数的类型上限
泛型参数的类型 允许传入 T,以及 T 的子类
| // 系统的类 ArrayList 声明了一个泛型 T | |
| class ArrayList<T>{ | |
| } | |
| // Type mismatch.Required:  ArrayList<Int> , but Found:ArrayList<Number> | |
| // 虽然 Int 是 Number 的子类,但 kotlin 认为 ArrayList<Number>,不是 ArrayList<Int > 的子类,所以会编译报错 | |
| val arrayList:ArrayList<Number> = ArrayList<Int>()// 编译报错 | |
| // 在定义处使用 out 关键字声明,允许传入的泛型参数可以是 T 以及 T 的子类 | |
| class ArrayList<out T>{ | |
| } | |
| // 也就是传入的泛型参数可以是 Number 及 Number 的子类 Int,Double,Float.... | |
| val arrayList:ArrayList<Number> = ArrayList<Int>()// 编译正常 | |
| // 使用处使用 out 关键字声明 | |
| val arrayList:ArrayList<out Number> = ArrayList<Int>()// 编译正常 | 
# in 约束泛型参数的类型下限
泛型类型限定为 T 及 T 的父类
| // 在定义处使用 out 关键字声明,允许传入的泛型参数可以是 T 以及 T 的子类 | |
| class ArrayList<T>{ | |
| } | |
| val arrayList:ArrayList<Int> = ArrayList<Number>()// 编译报错 | |
| class ArrayList<in T>{ | |
| } | |
| // 也就是传入的泛型参数可以是 Number 及 Number 的子类 Int,Double,Float.... | |
| // 使用处使用 out 关键字声明 | |
| val arrayList:ArrayList<Int> = ArrayList<Number>()// 编译正常 | |
| val arrayList:ArrayList<in Int> = ArrayList<Number>()// 编译正常,此时 in 可写可不写 | 
# 总结
| 泛型种类 | Java 中代码示例 | Kotlin 中代码示例 | 说明 | 
|---|---|---|---|
| 泛型类型 | class Box<T> | class Box<T> | 泛型类型 | 
| 泛型方法 | <T> T fromJson(String json, Class<T> tClass) | fun <T> fromJson(json: String, tClass: Class<T>): T? | 泛型函数 | 
| 有界类型参数 | class Box<T extends Comparable<T> | class Box<T : Comparable<T>> | 泛型类型约束 | 
| 上界通配符 | void sumOfList(List<? extends Number> list) | fun sumOfList(list: List<out Number>) | 泛型上限约束 | 
| 下界通配符 | void addNumbers(List<? super Integer> list) | fun addNumbers(list: List<in Int>) | 泛型下限型约束 | 
