------《Kotlin系列之泛型》
Kotlin 中也有泛型的概念,和 Java 中的类似,但又不尽相同,所以可以通过下面的几个方面去看一下:
一、Kotlin中的泛形
Kotlin 泛型的本质也是参数化类型,并且提供了编译时强类型检查,实际上也是伪泛型,和 Java 泛型类型一样。
泛形类
class Test<T>(t: T) {
var value = t
}
泛型接口
interface IAnimal<T> {
fun <T> test()
}
泛型方法
fun <T> initAnimal(param: T) {
var value = param
}
二、Kotlin泛形与Java区别
Kotlin泛型与Java泛型大部分都是相同的,但是语言特性导致有部分差异。
Java泛型不可调用泛型的方法,Kotlin可以
// Java语法不可以直接调用泛型T的方法
private <T> void fill(ArrayList<T> numbers) {
}
// Kotlin通过内联机制,可以使用泛型T的方法
inline fun <reified T> printGenerality(data: T) {
}
原因分析:泛型只在编译期间有效,运行期间会被擦除,所以泛型信息会消失,Java基于栈的形式调用方法得不到泛型的具体类型,Kotlin通过内联机制,编译期间是把方法直接添加到了对应的代码中,不存在栈调用的问题,所以可以通过上下文推导出泛型的具体类型。
友情提示:内联方法慎用return,会导致调用方直接返回
通配符与协变型变
在 Kotlin 中
上边界通配符: out 相当于 <? extends T> 适用于生产者也就是用来读取的对象
//Java : <? extends T>
Anmal<? extends dog> dog
//Kotlin : out
Anmal<out dog> dog
下边界通配符in 相当于 <? super T> 适用于消费之也就是用来写入的对象
//Java : <? super T>
Anmal<? super world> world
//Kotlin : out
Anmal<in world> world
除了写法上的区别它还有功能上的区别
使用处型变
在 Java 中,上下界通配符只能用在参数、属性、变量或者返回值中,不能在泛型声明处使用,所以才叫做使用处型变。
在Kotlin中java这种使用处型变被叫做类型投影
声明处型变
但不同的是,Kotlin 还提供 Java 所不具备的声明处型变。
顾名思义,Kotlin 提供的 out 和 in 两个型变关键字还可以用于泛型声明的时候。
public interface Collection<out E> : Iterable<E> {
...
}
// 错误,这里只能用val,不能用var
class Source<out T>(var t: T) {
...
}
在声明处设置 out 后,使得了在 Kotlin 中,Collection 安全的作为 Collection 的父类使用,但 E 被标记为 out 后,E只能被输出而不能写入。
interface Comparable<in T> {
operator fun compareTo(other: T): Int
}
fun demo(x: Comparable<Number>) {
x.compareTo(1.0) // 1.0 拥有类型 Double,它是 Number 的子类型
// 因此,我们可以将 x 赋给类型为 Comparable <Double> 的变量
val y: Comparable<Double> = x
}
Comparable 在声明处设置 in 后,x 就可以和 Number 或它的子类进行比较了。
星投影
当我们不知道泛型参数的类型信息时,但仍需要安全的使用它时,可以使用星投影,用星号*表示,星投影和 Java 中的原始类型很像,但星投影是安全。
val array1: Array<B> = arrayOf(B(), B(), B())
val array2: Array<*> = array1
使用星投影,我们可以将array1赋值给array2,但由于此时array2并不知道泛型参数的类型,所以不能对array2进行数据写入的操作,但可以从中读取数据:
array2[0] =A() //编译器会报错
val a = array2[0] // 正常
可以看出,星投影更适合那些泛型参数的类型不重要的场景
可以用下面官方说法理解一下
Function<*, String> 表示 Function<in Nothing, String>;
Function<Int, *> 表示 Function<Int, out Any?>;
Function<*, *> 表示 Function<in Nothing, out Any?>