您当前的位置: 首页 > 

代码与思维

暂无认证

  • 0浏览

    0关注

    163博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

90%的人都弄不明白的泛型:泛型缺陷与应用场景

代码与思维 发布时间:2022-06-21 13:54:10 ,浏览量:0

泛型对于每个开发者而言并不陌生,平时在项目中会经常见到,但是有很多小伙伴们,每次见到通配符 ? 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            
关注
打赏
1665387627
查看更多评论
0.0395s