kotlin 实战之泛型与逆变协变总结,震惊
用来限定类型的上界,也就是常说的协变,我们只能把它当作 extends 后面的 E 类型来读取,且读取是安全的类型转换,但是不能写入,写入会导致编译错误,因为写入可能是不安全的类型转换。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利
与 java 一样,kotlin 的泛型用来表示变量类型的参数化。一个简单的泛型类定义使用样例:
class Generics(t: T) {
var tmp: T = t
}
/**
运行结果:
class java.lang.String
class cn.yan.test.Generics
class java.lang.String
class cn.yan.test.Generics
*/
fun testRun() {
val generics: Generics = Generics(“666”)
println(generics.tmp.javaClass)
println(generics.javaClass)
//不像 java 没有<>就是 Object,kotlin 这里可以自动依据构造参数类型推断出是 String 类型
val generics1 = Generics(“666”)
println(generics1.tmp.javaClass)
println(generics1.javaClass)
}
一个简单的泛型函数定义如下:
//泛型函数的定义声明
fun get(t: T): T = t
/**
调用
*/
fun testRun() {
val v1 = get(“1233”)
val v2 = get(12)
val v3 = get(“1233”) //等价于v1,自动推断
}
泛型约束之协变(covariant)与逆变(controvariant)
关于泛型协变与逆变概念其实来自 java,在我们深入搞懂 kotlin 的泛型之前,我们有必要先巩固下 java 的泛型协变与逆变。以 java 代码为例子:
//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】
//java 代码
//表示可以往这个泛型集合放置任何类型对象
List
//表示可以往这个泛型集合只能放置String对象
List
//在 java 中不能把 List 类型变量赋值给 List,因为他们不是父子类关系
List list1 = new ArrayList();
//假设如果这么做被允许,则我们做如下代码,list2.add(new Date()); String str = list.get(0); 这会导致类型转换异常。
List list2 = list1; //编译失败
我们知道,在 java 中为了解决上面赋值问题,其提供了类型通配符的概念。如下是一个 java 样例:
//java 代码
//表示我们可以给这个变量里面 add Object 类型成员或者 Object 子类类型成员。
List<? extends Object> list;
我们继续看一种 java 场景:
//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】
//java 代码
interface Collection {
void addAll(Collection items);
}
void addAll(Collection to, Collection from) {
//理论上我们觉得 String 可以赋值给 Object,但是普通泛型中他们没有直接关系。
//无法编译通过,因为尝试赋值和接收的不是一个类型也不是父子类型关系。
to.addAll(from);
}
通过 java 对上面案例的改进写法如下 java 案例:
//java 代码
interface Collection {
void addAll(Collection<? extends E> items);
}
void addAll(Collection to, Collection from) {
//通配符保证了编译通过,也可以安全的从 to 中读取元素,然后当作 Object 类型来使用。
to.addAll(from);
}
通过上面例子可以发现,java 中Collection<String>是Collection<? extends Object>的子类型,但不是Collection<Object>的子类型。? extends用来限定类型的上界,也就是常说的协变,我们只能把它当作 extends 后面的 E 类型来读取,且读取是安全的类型转换,但是不能写入,写入会导致编译错误,因为写入可能是不安全的类型转换。反之,? super用来限定类型的下界,也就是常说的逆变,逆变是用来保证写入安全的,但是不能读取,有可能类型是不安全的转换。
我们如果只从中读取数据而不写入内容则称为协变,如果只向里面写入数据而不读取数据则称为逆变。
有了上面 java 泛型协变逆变的概念,现在我们再来看看 kotlin 的泛型。如下 kotlin 案例:
//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】
class Generics(t: T) {
private var tmp: T = t
fun get(): T = this.tmp
}
/**
运行结果:
test
*/
fun testRun() {
val t1 = Generics(“test”)
val t2: Generics = t1
println(t2.get())
//编译报错 Type mismatch. Required: Generics Found: Generics
//val t3: Generics = t2
}
上面代码如果 t3 想编译通过需要修改代码为如下:
//kotlin 协变用 out 表示只能读取不能写入
class Generics(t: T) {
private var tmp: T = t
fun get(): T = this.tmp
//编译错误 参数 t 爆红 Type parameter T is declared as ‘out’ but occurs in ‘in’ position in type T
//fun set(t: T) = this.tmp = t
}
/**
运行结果:
test
test
*/
fun testRun() {
val t1 = Generics(“test”)
val t2: Generics = t1
println(t2.get())
val t3: Generics = t2
println(t3.get())
}
如上就能保证 t3 类型安全读取,但是可以看到 Generics 中的 set 方法是无法编译通过的,因为 T 是 out 的,只能读取不能当参数写入,所以要想写入得对上面代码改为如下:
//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】
//kotlin 协变用 out 表示只能读取不能写入
//kotlin 逆变用 in 表示只能写入不能读取
class Generics<out T, in M>(t: T, m: M) {
private var tmp: T = t
private var mm: M = m
fun get(): T = this.tmp
fun set(arg: M) {
this.mm = arg
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。






既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上我搜集整理的2019-2021BATJ 面试真题解析,我把大厂面试中常被问到的技术点整理成了PDF,包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
《960全网最全Android开发笔记》

《379页Android开发面试宝典》
历时半年,我们整理了这份市面上最全面的安卓面试题解析大全
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。
如何使用它?
1.可以通过目录索引直接翻看需要的知识点,查漏补缺。
2.五角星数表示面试问到的频率,代表重要推荐指数

《507页Android开发相关源码解析》
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

腾讯、字节跳动、阿里、百度等BAT大厂 2019-2021面试真题解析

资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图
索引直接翻看需要的知识点,查漏补缺。
2.五角星数表示面试问到的频率,代表重要推荐指数
[外链图片转存中…(img-8v7KYCgN-1711657224674)]
《507页Android开发相关源码解析》
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
[外链图片转存中…(img-iYSi25YF-1711657224674)]
腾讯、字节跳动、阿里、百度等BAT大厂 2019-2021面试真题解析
[外链图片转存中…(img-onyIBEWv-1711657224674)]
资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图
更多推荐


所有评论(0)