秒懂Kotlin之彻底弄懂形变注解out与in
[版权申明] 非商业目的注明出处可自由转载
博文地址: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 variance和Use-site variance 。其通过两个关键字out
和in
来实现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 variance与Use-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()}
})
此种情况下out
和in
是在声明时候使用的,所以叫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中令初学者费解的out
与in
关键字就彻底将完了,相信你应该秒懂了。如果还是不懂,说明你太早看到这篇文章拉,建议你先收藏,以后等水平提高了再回来看看。
对了,记得点赞,分享。
暮云收尽溢清寒,银汉无声转玉盘。此生此夜不长好,明月明年何处看。《阳关曲 中秋月》苏轼
参考文章:
- Generics
- The Ins and Outs of Generic Variance in Kotlin
秒懂Kotlin之彻底弄懂形变注解out与in相关推荐
- 秒懂Kotlin之彻底弄懂属性(Property)Part2
[版权申明] 非商业目的注明出处可自由转载 博文地址: https://blog.csdn.net/ShuSheng0007/article/details/109071084 出自:shusheng ...
- 秒懂Kotlin之协变(Covariance)逆变(Contravariance)与抗变(Invariant)
[版权申明] 非商业目的注明出处可自由转载 博文地址:https://blog.csdn.net/ShuSheng0007/article/details/108708218 出自:shusheng0 ...
- java接口防抖_彻底弄懂节流和防抖
节流和防抖 这两个东西,你肯定听过,就是两种优化浏览器性能的手段.相关文章你肯定也看过,如果还是不太清楚,没关系,看完这篇短文,相信你能轻松理解其中差别. 防抖(deounce) 我们先说防抖吧,这里 ...
- 职称计算机证是继续教育的内容吗,豆腐网教你一分钟弄懂继续教育学时认定表及上传注意事项~...
原标题:豆腐网教你一分钟弄懂继续教育学时认定表及上传注意事项~ 大家好,我是豆腐网王老师,专注于南京工程师职称评审政策解读,关注我,让您轻松面对职称评审,少走弯路!!! 南京中高级职称申报已有段时间, ...
- 《繁凡的深度学习笔记》前言、目录大纲 一文让你完全弄懂深度学习所有基础(DL笔记整理系列)
<繁凡的深度学习笔记>前言.目录大纲 (DL笔记整理系列) 一文弄懂深度学习所有基础 ! 3043331995@qq.com https://fanfansann.blog.csdn.ne ...
- 一文弄懂元学习 (Meta Learing)(附代码实战)《繁凡的深度学习笔记》第 15 章 元学习详解 (上)万字中文综述
<繁凡的深度学习笔记>第 15 章 元学习详解 (上)万字中文综述(DL笔记整理系列) 3043331995@qq.com https://fanfansann.blog.csdn.net ...
- 一文让你完全弄懂逻辑回归和分类问题实战《繁凡的深度学习笔记》第 3 章 分类问题与信息论基础(上)(DL笔记整理系列)
好吧,只好拆分为上下两篇发布了>_< 终于肝出来了,今天就是除夕夜了,祝大家新快乐!^q^ <繁凡的深度学习笔记>第 3 章 分类问题与信息论基础 (上)(逻辑回归.Softm ...
- 看完弄懂,明年至少加 5K
看完弄懂,明年至少加 5K
- 彻底弄懂flex布局
目前在不考虑IE以及低端安卓机(4.3-)的兼容下,已经可以放心使用flex进行布局了.什么是flex布局以及它的好处,这里就不再赘述. 在这篇文章里,想说说flex布局的属性语法及其细节.那么网上也 ...
最新文章
- Java项目:(小程序)全套商城系统(spring+spring mvc+mybatis+layui+微信小程)
- ADF Jar包循环引用会出问题
- 开发日记-20190701 关键词 读书笔记《Linux 系统管理技术手册(第二版)》DAY 7
- 即时通讯:XMPP基础
- 大学计算机实验vfp,大学计算机基础VFP实验教材26页.doc
- python作用域链_具有动态特性的Python嵌套作用域
- 基于IdentityServer的系统对接微信公众号
- 29. ExtJs - Struts2 整合(1) - 登录页面
- 机器学习算法概述:随机森林逻辑回归
- 数据结构与算法python—10.二叉树题目leetcode总结
- elasticsearch sql插件 2.4及以下版本配置
- php函数find的用法,fleaphp crud操作之findByField函数的用法
- vbs表白代码+整人代码,抖音vbscript表白代码
- 鲁班学院java高级架构师_鲁班学院三期java架构师
- Clover 驱动文件夹_通过AppleALC,轻松解决苹果声卡驱动的问题.
- Linux实现黑客帝国炫酷效果
- android动态指示箭头,android – 自定义选项卡指示器(箭头像指示器)
- 【华为二面】2020/3/25_华为第二次技术面试_45分钟
- vc 调用matlab figure 画图
- 男生哪个瞬间让你心疼?