Kotlin学习(一)—Kotlin的泛型

前言

在Kotlin中使用泛型的方式跟Java大致相似,其中也有一些特性的差异。不管是Java中的泛型仍是Kotlin中的泛型,总有些概念会让人产生困惑。接下来回结合Java的泛型来学习Kotlin的泛型。安全

Kotlin中泛型的使用

在泛型的使用中,最经常使用到的就是泛型函数以及泛型类。在介绍这两种方式的使用以前,先介绍一下泛型的类型参数。app

泛型类型参数

泛型的类型参数就是在声明泛型时定义的类型形参,代表了在使用泛型时定义的一种类型。在泛型实例化是类型形参就被替换成了类型实参。好比:List  实例化为   List时,类型形参T就被替换成了类型实参String。函数

因为泛型是在Java 1.5时引入Java的,为了兼容老版本,在Java中容许使用没有类型形参的泛型。好比:List list = new ArrayList();这种生命是容许存在的。可是在Kotlin中泛型声明必须声明类型形参或者可以推导出类型形参。好比:val list = listof("a", "b");类型形参被推倒为String类型或者List直接声明为String类型。学习

泛型函数以及泛型类

//泛型函数
fun <T> someFunc(item: T): List<T> {
    // do something
}
复制代码
//泛型类
class Hello<T> {
    val value: T
}
复制代码

能够看到,在kotlin中使用泛型函数跟泛型类的方式与Java大体相同。除此以外,Kotlin还支持为一个类型制定多个约束的特性。ui

参数类型约束

在Kotlin中能够为类型参数指定约束,好比:fun  sum() T,这个泛型函数指定了类型参数的上限为Number类型,那个类型参数只能是Number或者Number的子类。这个在Java中的表示是extends实现,即:spa

code

处了上面的约束外,Kotlin还能够指定多个约束。接口

fun <T> someFunc(value: T) where T : CharSequence, T : Appendable {
	if (!value.endsWith('.')) {
		value.append('.')
	}
}
复制代码

上面这个泛型函数就指定了多个类型参数约束,在上面的状况下,类型参数必须实现CharSequence和Appendable两个接口。get

类型参数的空与非空:在Kotlin中每一个类型都有空与非空两种状况,实现泛型时也是如此。好比:List<String?>声明类型参数为一个可空的String类型,而List声明类型参数为不可空的String类型。string

运行时的泛型

和Java同样,在运行时Kotlin的类型信息也会被擦除,类型擦除随之带来的就是类型的消失。

类型擦除在Kotlin中的影响

  • 函数参数受到类型擦除的影响,好比:fun func1(list: List); fun func2(list: List);这两个使用List泛型,受到类型擦除的影响,在运行时,没法分辨两个函数参数的差别;
  • 类型检查,在类型擦书后,运行时没法检查对应的类型。好比 value is List,在Kotlin中的替代方式是value is List<*>,利用星号投影检查。

实化类型参数

实化类型参数的意思就是可使用类型参数。这个特性是Kotlin中加入的,一般是在内联函数

inline fun <reified T> isA(value: Any) = value is T
复制代码

能够看到在内联函数中能够直接使用类型参数T。这样的代码在普通函数中是不能正常编译的(会爬出异常Error: Cannot check for instance of erased type: T)。能够在内联函数中使用是由于内联函数直接以字节码的形式插入到调用的地方,因此在运行时能够获取到类型实参。还有就是reified关键字的做用就是声明了类型参数在运行时不被擦除。

Kotlin中的型变

不变型

Kotlin的不变型指的是:例如,对于两种任意类型A和B,MutableList既不是MutableList的子类型也不是超类型,那么成为在该类型参数上是不变型的(Java中全部的类型都是不变型的)。

协变

在Kotlin中对于一个泛型类,若是A是B的子类型, SomeClass就是SomeClass的子类型,也就是说子类型被保留了,这样就是协变。

//类被声明成在T上协变
class SomeClass<out T> {
	fun someFinc(): T
}
复制代码

上面的代码中就是声明协变的方式,即加入out关键字。协变只能生产类型T而不能消耗类型T,好比:只能get不能set,也就是协变是只读的。

在Java中与之对应的是<? extends T>的上界通配符。

逆变

在Kotlin中逆变能够看作是协变的镜像,下面是声明逆变的方式。

//声明逆变类型
interface Comparator<in T> {
	fun compare(e1: T, e2: T): Int {} //声明逆变使用in关键字
}
复制代码

逆变能够写入,可是返回只能是基础类型。

在Java与之对应的是<? super T>下界通配符。

星号投影

而在 Kotlin 中,在参数类型未知时,能够用星投影来安全的使用泛型。可是MutableList<*>与MutableList<Any?>是不同的。MutableList< * >至关于MutableList<out Any?>,是只读的。由于不明确具体类型的状况下,读是安全的,写是不安全的。

在Java中与之对应的是<?>无界通配符。

总结

Kotlin中的泛型与Java是相同的,处了几个Kotlin新加入的特性(好比:多约束类型,实化参数等),其余都与Java相通。

以上内容并无讲明更多的细节,只是列出了Kotlin中泛型的内容以及与Java泛型的联系。感兴趣的同窗能够继续深刻学习。

相关文章
相关标签/搜索