泛型对于每个开发者而言并不陌生,平时在项目中会经常见到,但是有很多小伙伴们,每次见到通配符 ? extends 、 ? super 、 out 、 in 都傻傻分不清楚它们的区别,以及在什么情况下使用。
通过这篇文章将会学习到以下内容。
- 为什么要有泛型
- Kotlin 和 Java 的协变
- Kotlin 和 Java 的逆变
- 通配符 ? extends 、 ? super 、 out 、 in 的区别和应用场景
- Kotlin 和 Java 数组协变的不同之处
- 数组协变的缺陷
- 协变和逆变的应用场景
在 Java 和 Kotlin 中我们常用集合( List 、 Set 、 Map 等等)来存储数据,而在集合中可能存储各种类型的数据,现在我们有四种数据类型 Int 、 Float 、 Double 、 Number,假设没有泛型,我们需要创建四个集合类来存储对应的数据。
class IntList{ }
class Floatlist{}
class DoubleList{}
class NumberList{}
......
如果有更多的类型,就需要创建更多的集合类来保存对应的数据,这显示是不可能的,而泛型是一个 “万能的类型匹配器”,同时又能让编译器保证类型安全。
泛型将具体的类型( Int 、 Float 、 Double 等等)声明的时候使用符号来代替,使用的时候,才指定具体的类型。
// 声明的时候使用符号来代替
class List{
}
// 在 Kotlin 中使用,指定具体的类型
val data1: List = List()
val data2: List = List()
// 在 Java 中使用,指定具体的类型
List data1 = new List();
List data2 = new List();
泛型很好地帮我们解决了上面的问题,但是随之而来出现了新的问题,我们都知道 Int 、 Float 、 Double 是 Number 子类型, 因此下面的代码是可以正常运行的。
// Kotlin
val number: Number = 1
// Java
Number number = 1;
我们花三秒钟思考一下,下面的代码是否可以正常编译。
List numbers = new ArrayList();
答案是不可以,正如下图所示,编译会出错。
这也就说明了泛型是不可变的,IDE 认为 ArrayList 不是 List 子类型,不允许这么赋值,那么如何解决这个问题呢,这就需要用到协变了,协变允许上面的赋值是合法的。
Kotlin 和 Java 的协变- 在 Java 中用通配符 ? extends T 表示协变,extends 限制了父类型 T,其中 ? 表示未知类型,比如 ? extends Number,只要声明时传入的类型是 Number 或者 Number 的子类型都可以
- 在 Kotlin 中关键字 out T 表示协变,含义和 Java 一样
现在我们将上面的代码修改一下,再花三秒钟思考一下,下面的代码是否可以正常编译。
// kotlin
val numbers: MutableList = ArrayList()
// Java
List
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?