朱涛 · Kotlin 编程第一课
朱涛
Google 认证的 Kotlin、Android 开发者专家,博客“Kotlin Jetpack 实战”作者
6717 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 50 讲
朱涛 · Kotlin 编程第一课
15
15
1.0x
00:00/00:00
登录|注册

10 | 泛型:逆变or协变,傻傻分不清?

你好,我是朱涛。这节课我们来学习 Kotlin 的泛型(Generics),包括泛型基础、使用处型变、声明处型变以及星投影。
泛型,这个概念在很多编程语言里面都存在。在中大型软件开发当中,我们对泛型的使用也十分频繁,因为它可以让我们在不同类型之间复用相似的逻辑代码
不管是 Android 领域,还是后端领域,泛型在软件的架构当中都有着举足轻重的地位。只有透彻理解了泛型,我们才能理解各种设计模式,进而才可能设计出合理的软件架构。
然而,想要学好泛型却不是一件容易的事情。这是因为,泛型实在太抽象了。
我们都知道,程序其实是对真实世界的抽象,比如我们在前面实战课里写的计算器程序,现实生活当中就有计算器这个东西,我们想要在电脑里写一个抽象的计算器程序,也不会那么难理解,因为它和现实生活相关。可是泛型,它是对程序的抽象。程序本来就已经够抽象了,我们还要在它的基础上再做一次抽象。
这样一来,泛型和我们真实的物理世界差了两层抽象,因此,泛型对于我们人类来说,会显得尤为虚无缥缈。
不过,程序其实也是源自于生活的。所以在这节课里,我会尽量用生活中的例子来给你解释下 Kotlin 的泛型概念,让你能更直观、更立体地感知到泛型与现实生活的联系,然后,你也能够从这些生活的场景中,更深刻地理解并掌握 Kotlin 的泛型,从而为你将来构建大型软件打好基础。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Kotlin泛型是软件开发中重要的概念。本文通过生动的例子和清晰的解释,帮助读者快速了解Kotlin泛型的基础知识和应用场景。文章首先介绍了泛型基础部分,通过遥控器类的例子说明了泛型的作用,以及如何使用泛型来实现代码逻辑的复用。接着讨论了泛型的不变性问题,并介绍了逆变和协变的概念。通过具体的代码示例和生活场景,读者可以更直观地理解泛型的应用和型变的概念。在逆变部分,作者以遥控器和电视机的关系为例,说明了逆变的概念及解决方法。在协变部分,以点外卖的场景为例,介绍了协变的概念及解决方法。最后,提到了Java和Kotlin的型变语法对比,强调了Kotlin相对简洁的语法。另外,文章还介绍了Kotlin中的“星投影”概念,以及在不确定泛型实参类型时的应用场景和解决方法。通过这些内容,读者可以快速了解Kotlin泛型的基本概念和高级特性,为进一步深入学习和实践打下良好的基础。文章通过生动的例子和清晰的解释,帮助读者快速了解Kotlin泛型的基础知识和应用场景。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《朱涛 · Kotlin 编程第一课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(32)

  • 最新
  • 精选
  • 白乾涛
    我觉得Java的 <? extends T> <? super Object> 语法不抽象呀,相比 kotlin 中的 in out 反而更清晰

    作者回复: 也许是角度不一样。这里,我觉得抽象的原因是这样的:Kotlin的in out,我一下就能反应过来,in是参数,out是返回值。但<? extends T> <? super Object>就会让我有点懵,不知道哪个该用在什么地方。

    2022-01-20
    4
    19
  • A Lonely Cat
    Java中的协变:<? extends T> Java中的逆变:<? super Object> Java中的“星投影”:<?>

    作者回复: 感谢这位同学的补充~

    2022-01-19
    2
    14
  • $Kotlin
    声明处型变无法支持又有in又有out,只能在使用处根据情况型变。

    作者回复: 赞~

    2022-01-19
    2
    12
  • 白乾涛
    协变:<? extends T> out-作为返回值-可以读取,不可以写入 逆变:<? super T> in-作为参数-可以写入,不可以读取(只能以Object读取)

    作者回复: 很好的总结,赞~

    2022-02-09
    3
    9
  • 白乾涛
    老师,文稿中说下面的代码会报错,实际上并不会报错呀 open class Animal() class Dog : Animal() class Cat : Animal() fun foo(list: MutableList<Animal>) { list.add(Dog()) val animal: Animal = list[0] } fun main() { foo(mutableListOf(Cat())) // 需要父类集合,传入子类集合 }

    作者回复: 嗯……确实,编译器把子类又推导成父类集合了。这里应该限定泛型实参的:mutableListOf<Cat>(Cat()) 感谢纠正~

    2022-02-09
    4
  • neo
    从型变的父子关系来分类的话,分为逆变和协变 泛型作为参数,用 in;泛型作为返回值,用 out 这两个条规则有冲突的时候应该怎么办呢

    作者回复: 符合条件的话,可以用:@UnsafeVariance。如果泛型真的同时存在读取和写入的话,那么就属于泛型不变性的范畴了,也就是说,它无法支持逆变和协变。

    2022-04-18
    2
  • Paul Shan
    使用处的型变,可以使用星投影,更灵活,但是范围比较小。声明处的型变,解决的是泛型类本身的约束,一次定义,所有使用的地方都受到相应影响,星投影处也不例外,使用处不得修改。个人觉得优先使用声明处的型变,使用处的型变会导致不同的使用处,型变不同的情况,带来额外的复杂性。星投影我在实际中基本没用过,老师能否举一个实际中用星投影能很好解决问题的场景。

    作者回复: 使用处,声明处的总结很棒!星投影的使用场景,往往是我们不需要范型的时候。

    2022-03-19
    1
  • Renext
    打卡

    作者回复: 加油~

    2022-01-24
    1
  • 阶前听雨
    很赞,基本能分清了,再多看几遍以加深理解。

    作者回复: 泛型确实比较抽象,要多体会,加油哈~

    2022-01-23
    1
  • louc
    历史上最好的讲泛型,通俗易懂

    作者回复: 看到你的回复我真的很高兴,希望你继续坚持学习下去~

    2022-04-30
收起评论
显示
设置
留言
32
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部