[版权申明] 非商业目的注明出处可自由转载
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/108759370
出自:shusheng007

文章首发于个人博客

文章目录

  • 概述
  • 泛型型变
    • 协变(out)
    • 逆变(in)
  • 总结

概述

本文承接于上一篇:秒懂Kotlin之协变(Covariance)逆变(Contravariance)与抗变(Invariant),一定要先阅读这一篇文章,再阅读本文,不然看不懂!

上篇讲到Java中泛型是抗变的,但是数组却是协变的。Kotlin做的更彻底,不仅泛型是抗变的就连数组也变成抗变的了。

下面的代码是编译不过的

val strArray:Array<String> = arrayOf("shu","sheng","007")
val array:Array<Any> = strArray

报错:

Type mismatch: inferred type is Array<String> but Array<Any> was expected

泛型型变

官方文档见:Variance

Kotlin中没有通配符,取而代之的是 Declaration-site varianceUse-site variance 。其通过两个关键字outin来实现Java中的? extends? super的功能.

假设我们有如下两个类和一个接口

open class Animal
class Dog : Animal()interface Box<T> {fun getAnimal(): Tfun putAnimal(a: T)
}

协变(out)

我们要定义一个方法,参数类型为Box<Animal>,但是我们希望可以传入Box<Dog>即希望可以发生协变

Java实现

private Animal getOutAnimalFromBox(Box<? extends Animal> box) {Animal animal = box.getAnimal();
//       box.putAnimal(? ) 没有办法调用修改方法,因为我们不知道?究竟是一个什么类型,没办法传入return animal;
}

Kotlin对应的实现为:

fun getAnimalFromBox(b: Box<out Animal>) : Animal {val animal: Animal = b.getAnimal()
//    b.putAnimal(Nothing) 无法调用,因为方法需要一个Nothing类型的对象,但是在kotlin中无法获取return animal
}

此方法可以接受Box<Dog>类型的参数了。

可见此处使用out 代替了? extends。从结果来看确实更合适一点,因为传入的参数只能提供值,而不能消费值。由于out是在方法调用的参数中标记的,处于使用端,所以叫Use-site varianceUse-site variance对应的就是Declaration-site variance了。

我们发现接口Box<T>中既有消费值的方法fun putAnimal(a: T),又有提供值的方法fun getAnimal(): T,导致我们必须在使用侧告诉编译器我们要使用哪一类方法。那我们可以在声明接口的时候告诉编译器吗?答案是肯定的,但是就需要将接口拆分为只包含提供值的方法的接口producer与只包含消费值的方法的接口consumer

//producer
interface ReadableBox<out T> {fun getAnimal(): T
}
//consumer
interface WritableBox<in T> {fun putAnimal(a: T)
}

拆分完接口并做了相应的声明后,就可以不在使用端使用out或者in了。

fun getAnimalFromReadableBox(b: ReadableBox<Animal>){val a: Animal = b.getAnimal()
}

上面的方法可以直接接受ReadableBox<Dog>类型的参数,给人的感觉好像是Kotlin使得泛型协变了。

getAnimalFromReadableBox(object :ReadableBox<Dog>{override fun getAnimal(): Dog {return Dog()}
})

此种情况下outin是在声明时候使用的,所以叫Declaration-site variance了。

逆变(in)

我们要定义一个方法,参数类型为Box<Dog>,但是我们希望可以传入Box<Animal>,即希望可以发生逆变

Java实现

private void putAnimalInBox(BoxJ<? super Dog> box){box.putAnimal(new Dog());Object animal= box.getAnimal();// 可以调用读取方法,但是返回的类型确实Object,因为我们只能确定?的大基类是Object
}

Kotlin对应实现

fun putAnimalInBox(b: Box<in Dog>){b.putAnimal(Dog())val animal:Any? = b.getAnimal()// 可以调用读取方法,但是返回的类型确实Any?,因为我们只能确定?的大基类是Any?
}

此方法可以接受Box<Animal>类型的参数了

可见此处使用in 代替了? super,从结果来看确实更合适一点,因为传入的参数只适合消费值,而不适合获取值,获取到的值失去了有用的类型信息。由于in是在方法调用的参数中标记的,处于使用端,所以叫Use-site variance

让我们来看一下使用Declaration-site variance实现逆变

fun putAnimalToWritableBox(b:WritableBox<Dog>){b.putAnimal(Dog())
}

上面的方法可以直接接受WritableBox<Animal>类型的参数,给人的感觉好像是Kotlin使得泛型逆变了。

putAnimalToWritableBox(object :WritableBox<Animal>{override fun putAnimal(a: Animal) {}
})

总结

kotlin中令初学者费解的outin关键字就彻底将完了,相信你应该秒懂了。如果还是不懂,说明你太早看到这篇文章拉,建议你先收藏,以后等水平提高了再回来看看。

对了,记得点赞,分享。

暮云收尽溢清寒,银汉无声转玉盘。此生此夜不长好,明月明年何处看。《阳关曲 中秋月》苏轼

参考文章:

  1. Generics
  2. The Ins and Outs of Generic Variance in Kotlin

秒懂Kotlin之彻底弄懂形变注解out与in相关推荐

  1. 秒懂Kotlin之彻底弄懂属性(Property)Part2

    [版权申明] 非商业目的注明出处可自由转载 博文地址: https://blog.csdn.net/ShuSheng0007/article/details/109071084 出自:shusheng ...

  2. 秒懂Kotlin之协变(Covariance)逆变(Contravariance)与抗变(Invariant)

    [版权申明] 非商业目的注明出处可自由转载 博文地址:https://blog.csdn.net/ShuSheng0007/article/details/108708218 出自:shusheng0 ...

  3. java接口防抖_彻底弄懂节流和防抖

    节流和防抖 这两个东西,你肯定听过,就是两种优化浏览器性能的手段.相关文章你肯定也看过,如果还是不太清楚,没关系,看完这篇短文,相信你能轻松理解其中差别. 防抖(deounce) 我们先说防抖吧,这里 ...

  4. 职称计算机证是继续教育的内容吗,豆腐网教你一分钟弄懂继续教育学时认定表及上传注意事项~...

    原标题:豆腐网教你一分钟弄懂继续教育学时认定表及上传注意事项~ 大家好,我是豆腐网王老师,专注于南京工程师职称评审政策解读,关注我,让您轻松面对职称评审,少走弯路!!! 南京中高级职称申报已有段时间, ...

  5. 《繁凡的深度学习笔记》前言、目录大纲 一文让你完全弄懂深度学习所有基础(DL笔记整理系列)

    <繁凡的深度学习笔记>前言.目录大纲 (DL笔记整理系列) 一文弄懂深度学习所有基础 ! 3043331995@qq.com https://fanfansann.blog.csdn.ne ...

  6. 一文弄懂元学习 (Meta Learing)(附代码实战)《繁凡的深度学习笔记》第 15 章 元学习详解 (上)万字中文综述

    <繁凡的深度学习笔记>第 15 章 元学习详解 (上)万字中文综述(DL笔记整理系列) 3043331995@qq.com https://fanfansann.blog.csdn.net ...

  7. 一文让你完全弄懂逻辑回归和分类问题实战《繁凡的深度学习笔记》第 3 章 分类问题与信息论基础(上)(DL笔记整理系列)

    好吧,只好拆分为上下两篇发布了>_< 终于肝出来了,今天就是除夕夜了,祝大家新快乐!^q^ <繁凡的深度学习笔记>第 3 章 分类问题与信息论基础 (上)(逻辑回归.Softm ...

  8. 看完弄懂,明年至少加 5K

    看完弄懂,明年至少加 5K

  9. 彻底弄懂flex布局

    目前在不考虑IE以及低端安卓机(4.3-)的兼容下,已经可以放心使用flex进行布局了.什么是flex布局以及它的好处,这里就不再赘述. 在这篇文章里,想说说flex布局的属性语法及其细节.那么网上也 ...

最新文章

  1. Java项目:(小程序)全套商城系统(spring+spring mvc+mybatis+layui+微信小程)
  2. ADF Jar包循环引用会出问题
  3. 开发日记-20190701 关键词 读书笔记《Linux 系统管理技术手册(第二版)》DAY 7
  4. 即时通讯:XMPP基础
  5. 大学计算机实验vfp,大学计算机基础VFP实验教材26页.doc
  6. python作用域链_具有动态特性的Python嵌套作用域
  7. 基于IdentityServer的系统对接微信公众号
  8. 29. ExtJs - Struts2 整合(1) - 登录页面
  9. 机器学习算法概述:随机森林逻辑回归
  10. 数据结构与算法python—10.二叉树题目leetcode总结
  11. elasticsearch sql插件 2.4及以下版本配置
  12. php函数find的用法,fleaphp crud操作之findByField函数的用法
  13. vbs表白代码+整人代码,抖音vbscript表白代码
  14. 鲁班学院java高级架构师_鲁班学院三期java架构师
  15. Clover 驱动文件夹_通过AppleALC,轻松解决苹果声卡驱动的问题.
  16. Linux实现黑客帝国炫酷效果
  17. android动态指示箭头,android – 自定义选项卡指示器(箭头像指示器)
  18. 【华为二面】2020/3/25_华为第二次技术面试_45分钟
  19. vc 调用matlab figure 画图
  20. 男生哪个瞬间让你心疼?

热门文章

  1. Windows下使用Eclipse开发Arduino程序
  2. Python 自动化工具pyautogui 安装过程详解
  3. Vuex入门(二)—— mutations详解
  4. 单链表基本操作C++
  5. C++实用工具类-ini配置文件解析
  6. char类型转int类型
  7. ARM汇编指令 SUB MOV LDR STR
  8. DB2文件系统已满的解决方法
  9. 2022年全球及中国高档皮具市场消费创新模式与盈利前景展望分析报告
  10. Docker配置镜像加速(CentOS 7系统)