时间:2021-05-19
前言
Kotlin 的泛型与 Java 一样,都是一种语法糖,只在源代码里出现,编译时会进行简单的字符串替换。
泛型是静态类型语言中不可缺少的一部分,Kotlin 的泛型定义和使用都类似 Java,但也有一些基于工程实践考虑的优化和改进。
泛型(Generics)其实就是把类型参数化,真正的名字叫做 类型参数,它给强类型编程语言加入了更强的灵活性。在 Java 中,只要是有类型的 API 元素,都可以泛型化,也就是泛型类、泛型接口、泛型方法和泛型属性,泛型类和泛型接口可以统称为泛型类型。其中最重要的是泛型类型和泛型方法,Kotlin 泛型系统继承了 Java 泛型系统,同时添加了一些强化的地方。
实化泛型参数
在 Java 中经常会定义这种方法:
<T> void someFunction(Class<T> clazz) { //...}这是因为 Java 的泛型擦除机制无法使用形如 T.class 来获取泛型的真实类型对象。但是在调用者看来,泛型却是实实在在的固定类型,所以这里借助 Kotlin 的内联函数 inline 可以实化泛型参数,在 Kotlin 中只需要这样:
fun <T> someFunction() { val clazz = T::class.java }泛型的协变、逆变
在 Java 中,定义带泛型的参数时为了更好的匹配目标类型,有 ? extends Type 和 ? super Type 两种形式,以 List 接口中的定义为例:
boolean addAll(Collection<? extends E> c);void sort(Comparator<? super E> c);addAll 方法中,Collection 中的泛型被定义成接收类型参数 E 的子类,这是因为需要读取也就 c 的值,所以需要保证 c 是 Collection 的子类;而 sort 方法中,则是需要类中的类型参数 E 能够被 Comparator 中的方法传入,所以也就需要保证 E 是 Comparator 类型参数的子类。
而 Kotlin 中,针对于这两种情况给了另外两个关键字:需要读取带泛型对象的值时,使用 out 来标记类型参数;需要传入类型参数的类型作为形参时,使用 in。
这两种关键字的命名的方向是不同的:Java 偏向于从原理的方向命名,而 Kotlin 的命名对于具体的使用场景更为直观。在 Kotlin 中,被 out 标记类型参数的类型称之为协变类型,它代表当 A 是 B 的子类时,C 也能作为 C 的子类使用;而被 in 标记类型参数的类型则相反,它代表当 A 是 B的子类时,C 是 C 的子类。
从方法参数的使用上来说,Kotlin 和 Java 似乎没有什么不同,而不同的地方在于 Kotlin 可以将这种定义作用在类型定义上,官方称之为声明点变型;与之相对应的,像 Java 这种在方法参数上定义的被称为使用点变型。
声明点变型在类型的声明时定义了该类型参数是用在入参还是出参上,之后在这个类中所有用到的地方都会直接调用该类型的定义名称来使用该类型的协变或者逆变。而 Java 中需要在每次使用时来重复说明该处需要协变还是逆变。Kotlin 也可以进行使用点变型,只要和 Java 一样,在声明处不进行说明,而只在使用时声明就可以了。
「*」投影
因为 Kotlin 源码中不允许忽略泛型参数,所以在一些泛型不重要的地方,就不可避免的使用 来表示。当使用 时,为了保证类型安全,官方建议的模式是将泛型定义为 的对象封装起来,写操作一般是安全的,因为 可以接收一切类型;对于读操作可以进行安全的转换,对于不匹配的类型进行统一处理。
泛型的注意点:
在java编程中类型系统最棘手的一部分是通配符类型。但是,在Kotlin编程中,是没有通配符,采用声明变化和类型投影来替代。
通配符的作用: 使用界限通配符增加API的灵活性。
在Java编程中一个常见的问题:
List<String> strs = new ArrayList<String>();List<Object> objs = strs; // !!! 这里会导致一个问题,在Java中是禁止这样做的objs.add(1); //将integer类型的数据添加到String 类型的列表中String s = strs.get(0); // !!! ClassCastException异常 : Integer类型不能转成String在Kotlin编程中:
一旦声明类型后,不能加入其它的类型数据,如下图所示。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文以实例形式讲述了C#泛型的用法,有助于读者深入理解C#泛型的原理,具体分析如下:首先需要明白什么时候使用泛型:当针对不同的数据类型,采用相似的逻辑算法,为了
Kotlin支持泛型,语法和Java类似。例如,泛型类:classHello(valvalue:T)valbox=Box(1)valbox1=Box(2)泛型函
扩展阅读c#基础系列1---深入理解值类型和引用类型c#基础系列2---深入理解String引言在上篇文章深入理解值类型和引用类型的时候,有的小伙伴就推荐说一说
首先看我们的源代码。复制代码代码如下:深入理解Javascriptconsole.log(this);深入理解Javascript我们知道,通过浏览器打开这个页
这篇文章的目的在于介绍Java泛型,使大家对Java泛型的各个方面有一个最终的,清晰的,准确的理解,同时也为下一篇《重新理解Java反射》打下基础。简介泛型是J