Kotlin 范型之泛型约束、类型投影、星号投影

Kotlin 范型之泛型约束、类型投影、星号投影_第1张图片

一. 泛型约束(Generic constraints)

Kotlin 跟 Java 一样,也拥有泛型约束。Java 使用 extends 关键字指明上界。

在 Kotlin 中使用 :代替 extends 对泛型的的类型上界进行约束。

1.1 Upper bounds

下面的代码,在调用 sum() 函数时,传入的参数只能是 Number 及其子类,如果是其他类型,则会报错。

fun  sum(vararg param: T) = param.sumByDouble { it.toDouble() }	
fun main() {	
    val result1 = sum(1,10,0.6)	
    val result2 = sum(1,10,0.6,"kotlin") // compile error	
}

Kotlin 默认的上界是 Any?,为何是 Any?而不是 Any 呢?

Any 类似于 Java 中的 Object,它是所有非空类型的超类型。但是 Any 不能保存 null 值,如果需要 null 作为变量的一部分,则需要使用 Any?Any?是 Any 的超类型,所以 Kotlin 默认的上界是 Any?

1.2 where 关键字

当一个类型参数指定多个约束时,在 Java 中使用 &连接多个类、接口。

class ClassA { }	
interface InterfaceB { }	
public class MyClass {	
    Class variable;	
}

而在 Kotlin 中,使用 where 关键字实现这个功能。下面的代码,T 必须继承 ClassA 以及实现 InterfaceB。

open class ClassA	
interface InterfaceB	
class MyClass(var variable: Class) where T : ClassA, T : InterfaceB

二. 类型投影(Type projections)

在上一篇文章《

如果对 MutableList 的参数类型使用 in 或者 out 修饰,会发生什么情况呢?

下面的代码说明了一切:

fun main() {	
    val list1:MutableList = mutableListOf()	
    list1.add("hello")	
    list1.add("world")	
    val list2:MutableList = mutableListOf()	
    list2.add("hello")  // compile error	
    list2.add("world")  // compile error	
    val list3:MutableList = mutableListOf()	
    list3.add("hello")	
    list3.add("world")	
    lateinit var list4:MutableList	
    list4 = list3;     // compile error	
}

使用 out 时,会报错,因为该参数只能出现在方法的返回类型。而使用 in 时,编译可以通过,因为该参数只能出现在方法的入参。

此时,list2 和 list3 分别表示一个受限制的 MutableList。在 Kotlin 中,这种行为被称之为类型投影。其主要作用是参数作限定,避免不安全操作。

正是由于 list3 是一个受限制的 MutableList,因此它赋值给 list4 报错也是可以理解了。

三.星号投影(Star-projections)

星号投影用来表明“不知道关于泛型实参的任何信息”。

类似于 Java 中的无界类型通配符 ?, Kotlin 使用星号投影 *

*代指了所有类型,相当于 Any?

例如:MutableList<*> 表示的是 MutableList

fun main() {	
    val list1 = mutableListOf()	
    list1.add("string1")	
    list1.add("string2")	
    printList(list1)	
    val list2 = mutableListOf()	
    list2.add(123)	
    list2.add(456)	
    printList(list2)	
}	
fun printList(list: MutableList<*>) {	
    println(list[0])	
}

正是由于使用 out 修饰以及星号投影的类型不确定性,会导致写入的任何值都有可能跟原有的类型冲突。因此,星号投影不能写入,只能读取。

四.总结

本文是 Kotlin 范型系列的最后一篇文章。本文讲述了 Kotlin 泛型约束、类型投影、星号投影的特性。范型是 Kotlin 的高级特性,相对于 Java 的范型,它拥有更多的概念。

该系列的相关文章:

关注【Java与Android技术栈】

更多精彩内容请关注扫码

Kotlin 范型之泛型约束、类型投影、星号投影_第2张图片

你可能感兴趣的:(Kotlin 范型之泛型约束、类型投影、星号投影)