实用 AI

可在线运行 AI 集合,涵盖 AI 文案生成、写作辅助、AI 绘图与照片修复、AI 配音、字幕生成、语音转录以及 AI 视频创作和数字人等多种 AI 服务

查看详情

Kotlin范型中的in和out关键字(协变和逆变)

深入学习Kotlin基础知识
2022-06-04 22:21 · 阅读时长7分钟

在使用kotlin的范型时,发现它比java多了两个关键字outin。在java的范型中常用的关键字是extends和super,所以我在想out和in和它们之间是否存在某些关系。关于java范型中的extends和super使用,可以参考Java范型的上限约束和下限约束

要说范型还是得从java的范型说起,我们知道java中的范型在编译之后就没有了,也是就是常提到的类型擦除,比如说下面这段代码。

加载中...

在编译之后就变成了这样。

加载中...

既然这样,那为什么还要用范型呢?为了保证类型安全,通过范型约束,我们可以在编译期间提前发现类型安全问题,而不是在运行时报错。比如说,如果没有范型,这段代码是可以编译通过的。

加载中...

但是在运行时会发生ClassCastException,如果使用了范型进行约束,那么在编译时就会报错,让开发者及时发现错误。

out关键字

但是类型约束也导致了一些问题,比如说我们有一个自定义的列表ZXList,和一个数据类Parent和Child。

加载中...

现在有一个Parent类型和一个Child类型的ZXList,我们想让两个ZXList合并,很自然地使用addAll方法,但是却发现编译不通过。

加载中...
加载中...

这就不符合正常逻辑了,按道理Child类型类型应该是能够兼容Parent类型的,但是上面这样addAll定义就是不能兼容,如果需要实现兼容,我们需要extends关键字把addAll方法定义改成这样。

加载中...

这样的意思是addAll里面的ZXList的范型类型只要是继承自T类型即可。而在kotlin中这些写法就变成了使用out关键字。

加载中...

以上就是out关键字的作用之一。我们知道按道理childList是兼容parentList的,但是我们却不能把childList赋值给parentList,即下面的java代码编译是无法通过的。

加载中...

但是在kotlin中,通过out关键字这也是可以实现的。

加载中...
in关键字

在java的范型中super这个关键字,最经典的应用示例就是List.sort(Comparator<? super E> c),还是以ZXList为例说明,假设ZXList也有一个sort方法,定义如下。

加载中...

另外有Animals、Dog和Cat三个类,定义如下。

加载中...

现在有两个ZXList分别是ZXList<Dog>和ZXList<Cat>,我们想让两个列表都通过age字段进行排序。

加载中...

运行后发现编译出错,dogList和catList不能使用Comparator<Animal>进行排序,这明显也不符合正常逻辑,Dog和Cat都是继承自Animal,为什么就不能使用Comparator<Animal>排序呢?其实也是有办法的,那就是使用super关键字,把ZXList的sort方法定义改成

加载中...

在kotlin中要实现这个效果就是使用in关键字,代码如下

加载中...
总结

kotlin中的out和in关键字主要用于强化范型的使用,kotlin中的<out T>相当于java中的<? extends T>,而<in T>就相当于<? super T>,但是inout关键字的功能要更强大一些,另外要注意的是java中的范型上限用的也是extends关键字,比如<T extends Animal>,kotlin中范型的上限用的是:,比如T : Animal

kotlin协变逆变outin