Java/Kotlin泛型学习回顾

240 阅读2分钟

1.## 泛型到底是什么?

**泛型的本质** → **类型参数化** → **要操作的数据类型** 可以通过 **参数的形式来指定**

### ① 边界限制

<T extends Entity> ,要求传入的泛型参数必须是 Entity类或它的子类,又称 泛型上界

限制上界的好处:可以直接 调用父类或父接口的方法

### ② 不变、协变、逆变

① 协变父子关系一致 → 子类也可以作为参数传进来 →  <? extends Entity>  → 上界通配符

Kotlin中使用 **out** 关键字表示协变 → **Response<out Entity>**

② 逆变父子关系颠倒 → 父类也可以作为参数传进来 →  <? super Article>  → 下界通配符

Kotlin中使用 **in** 关键字表示逆变 → **Response<in Entity>**

### ③ 何时用协变?何时用逆变?

**让子类也能传** → **协变(extends out)****让父类也能传** → **逆变(super in)**
**协变** → **能读不能写** (**能用父类型去获取数据**,不确定具体类型,不能传)
**逆变** → **能写不能读** (**能传入子类型**,不确定具体类型,不能读,但可以用Object读)

-   **生产者** → **extends/out** → **协变** → **对象只作为返回值传出**
-   **消费者** → **super/in** → **逆变** → **对象只作为参数传入**

总结

泛型本质:类型参数化,要操作的数据类型可以通过参数指定,类比函数,定义指定形参(数据类型),调用传入
实参(具体类型)。 语法表现:类比占位符,把类型确定推迟到创建对象或调用方法时,然后就是围绕这个占位
符制定的一系列语法规则。 泛型上界<T extends Entity>,传入类型参数需为Entity类或其子类,限制上界的
好处:直接调父类成员。 不变:编译器只能识别具体类型,Response<Entity>不等于Response<Article>,不
能互相替换。 型变:扩展参数的类型范围,但也导致不能按照泛型类型读取元素,根据定义型变位置分为:使
用处型变 和 声明处型变(Java没有)。 协变:Response<? extends Entity> 父子关系一致,能读不能写 (能
用父类型获取,不确定具体类型不能传) 逆变:Response<? super Article> 父子关系颠倒,能写不能读 (能
传子类型,不确定具体类型不能读,但可用Object读) PECS法则:生产者 → out/extends → 协变 → 返回值;
消费者 → in/super → 逆变 → 入参 泛型同时作为参数和返回值,没实际写入行为,可用@UnsafeVariance注解
解决 型变冲突。 Java假泛型 → 类型擦除 → 进JVM前用Object或限定类型替换 → 反射绕过 → 不实现真泛型原
因:向前兼容。 获取泛型具体类型 → 匿名内部类 + 反射,inline内联函数 + reified关键字(类型不擦除)