01. 泛型.md

01. 泛型.md

大鱼 449 2021-05-11

泛型

1. 泛型擦除

  1. 泛型擦除 在常量池里保留了泛型信息(getGernericType、getActualTypeArguments), retrofit就利用此原理

2. 泛型的原理

jdk5引入的新特性,为了向下兼容,虚拟机其实是不支持泛型的,java实现其实是一种伪泛型机制, 也就是说Java在编译期擦除了所有的泛型信息,这样Java就不需要产生新的类型到字节码,所有的泛型最终都是同一种类型,运行时不存在泛型信息

3. 编译器泛型擦除过程

  1. 检查泛型类型,获取目标类型
  2. 擦除类型变量,并替换为限定类型
  1. 如果泛型类型没有限定, 则用Object作为原始类型
  2. 如果有限定 则用XClass作为原始类型
  3. 如果有多个限定<T extends XClass & XClass2> 则使用第一个边界作为原始类
  1. 在必要时插入类型转换以保证类型安全
  2. 生成桥方法以在扩展时保持多态性

4. 泛型副作用

  1. 不能使用基本类型做T
  2. 不能使用instanceOf关键字
  3. 静态方法和静态类里无法使用,静态泛型方法可以使用
  4. 泛型会导致方法冲突, 擦除之后类型相同, 重复定义
  5. 泛型类无法直接创建实例
  6. 没有泛型数组, (Apple[] 父类是Fruit[],称作数组的协变,) 泛型无法确定是什么类型,无法进行协变

5. 泛型继承

  1. T相同, 类继承, 可以认为是继承关系
  2. T不相同,无法认为是继承关系,共同父类是Object

6. 通配符

  1. 上界通配符 Plate<? extends Fruit> 可以放Apple、Banana… 但是set方法没法传递子类对象, 可以通过反射放入(任意类型皆可,安全没法保证),读取随意
  2. 下界通配符 Plate<? super Fruit> 可以放Food… ,写入随意
  3. 非限定通配符 Plate<?> 不能读也不能写
  4. 所以入参用<? super Fruit>便于写入,出参用<? extends Fruit>便于读取, 详见ArrayList的copy方法