阿里面试官的面评 都可以看吗,一篇文章教你搞清楚,Android开发实用必备的几款插件
}
class MyList {
fun set(itme: CharSequence)
fun get(): CharSequence
}
复制代码
因为fun set(itme: String)可以接收的参数范围比fun set(itme: CharSequence)小,不符合第一条退推论,所以MyList不是MyList的子类型。
而添加了out之后,相当于告诉编译器把出错的方法删掉以保留子类型化:
class MyList {
fun get(): T {…}
}
class MyList {
fun get(): String
}
class MyList {
fun get(): CharSequence
}
此时fun get(): String返回值的范围比fun get(): CharSequence小,符合第二条推论,所以MyList是MyList的子类型。
逆变
除了不变型、协变,泛型类之间还有一种子类型关系:逆变。
逆变的意思是:类与其类型参数的抽象程度具有相反的变化方向。
换句话说:当类型参数变得更具体时,类却变得更抽象。当类型参数变得更抽象时,类却变得更具体。
逆变有一点反直觉,它想实现的效果是:List成为List是的子类型。
如果一个泛型类是逆变的,就意味着它在类的层面反转了类型参数的子类型关系
Kotlin 中,声明类在类型参数上是逆变的,需要添加in保留字:
class MyList{ … }
同样地,这需要付出代价:
class MyList {
fun set(item: T) {}
fun get(): T {…}//报错: Type parameter is declare as “in” but occur at “out” position in type T
}
当T被in修饰后,它只能出现在参数位,即它只能被泛型类消费而不能被生产。
由此可见:
out和int不仅限定了参数可以出现的位置,还限定了什么类可以成为子类型。
类型投影
生活中的投影,是把一个三维物体变成二维物体,投影看上去还是那个物体只是降了一维。
程序中的类型投影也是类似的意思:
将类型投影意味着保留该类型的有些能力,去掉另一些能力。通过类型投影可以动态地改变泛型类的子类型关系。
类型投影通常应用于将不变型的泛型类动态地转换成逆变或协变。
比如,MutableList就是不变型的:
public interface MutableList : List, MutableCollection {
// 类型参数出现在 out 位置
public fun removeAt(index: Int): E
// 类型参数出现在 in 位置
public fun add(index: Int, element: E): Unit
…
}
MutableList是不变型,所以泛型参数可随意出现在in或out位置。
但不变型有时候会缩小方法的适用范围,比如:
fun copy(source: MutableList, destination: MutableList){
for (item in source){
destination.add(item)
}
}
这是一个拷贝集合的方法,引入泛型是为了避免为每一种具体的类型都重新定义一遍方法。现在这个方法可以在任何数据类型相同的两个列表见拷贝内容。
但如果我想把一个字符串集合拷贝到可以包含任意对象的集合中怎么办?
val strings = mutableListOf( “a”, “b”, “c” )
val anys = mutableListOf()
copy( strings, anys )// 报错
因为copy()的定义要求源和目的集合具有相同的类型。
为了让copy()方法能适用于这种情况,可以这样改写:
fun <R: T, T> copy(source: MutableList, destination: MutableList){
for (item in source){
destination.add(item)
}
}
引入第二个泛型R,它是T的子类型,并指定它为源集合类型参数。
这个改动一下子扩展了source参数接受实参类型的范围,原本它只能和destination使用同样的类型,现在它可以使用所有destination的子类型。
运用变型可以简化这个改动:
fun copy(source: MutableList, destination: MutableList){
for (item in source){
destination.add(item)
}
}
source参数声明的地方,发生了out 类型投影,投影去掉了MutableList中所有消费类型参数的方法,保留了所有生产类型参数的方法。
虽然source参数丧失了部分能力,但牺牲总是有回报的,source所能接受实参的类型范围被扩展了。(碰巧,copy()方法体中也不需要source丧失的那部分能力。)
MutableList和MutableList的区别如下:
public interface MutableList {
// 类型参数出现在 out 位置的方法保持原样
public fun removeAt(index: Int): T
// 类型参数出现在 in 位置的方法被改写
public fun add(index: Int, element: Nothing): Unit
…
}
out保留字命令编译器去改写泛型类中所有消费类型参数的方法,将in位置的参数类型改成Nothing。
Nothing是所有类的子类,为啥要这样改呢?因为想让MutableList成为MutableList的子类型。
回忆一下子类型的 2 个推论:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。







既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)

Android开发除了flutter还有什么是必须掌握的吗?
相信大多数从事Android开发的朋友们越来越发现,找工作越来越难了,面试的要求越来越高了
除了基础扎实的java知识,数据结构算法,设计模式还要求会底层源码,NDK技术,性能调优,还有会些小程序和跨平台,比如说flutter,以思维脑图的方式展示在下图;

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
GC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算**
更多推荐



所有评论(0)