星投影
star projection(星投影)
Star<out T>
:如果T
的上界是TUpper
,那么Star<*>
就相当于Star<out T>
,这表示当T
的类型未知时,你可以Star<*>
当中安全地读取TUpper
类型的值。
Star<in T>
:Star<*>
就相当于Star<in Nothing>
,这表示你无法向其中写入任何值。
Star<T>
,如果T
的上界为TUpper
,那么Star<*>
就相当于读取时的Star<out TUpper>
以及写入时的Star<in Nothing>
。
如果泛型类型具有多个类型参数,则每个类型参数都可以单独投影。 例如,如果类型被声明为interface Function <in T, out U>
,我们可以想象以下星投影:
Function<*, String>
表示 Function<in Nothing, String>
;
Function<Int, *>
表示Function<Int, out Any?>
;
Function<*, *>
表示 Function<in Nothing, out Any?>
。
注意:星投影非常像 Java 的原始类型,但是安全。
示例代码
class Start<out T> {
}
class Star2<in T> {
fun setValue(t: T) {
}
}
class Star3<T>(private var t: T) {
fun setValue(t: T) {
}
fun getValue(): T {
return this.t
}
}
fun main(args: Array<String>) {
val star: Start<Number> = Start<Int>()
val star2: Start<*> = star
val star3: Star2<Int> = Star2<Number>()
val star4: Star2<*> = star3
//star4.setValue(3) //compile error
val star5: Star3<String> = Star3<String>("hello")
val star6: Star3<*> = star5
star6.getValue()
//star6.setValue("") //compile error
val list: MutableList<*> = mutableListOf("hello", "world", "hello world")
println(list[0])
//list[0] = "test" //compile error
}
泛型擦除
Kotlin 为泛型声明用法执行的类型安全检测仅在编译期进行。 运行时泛型类型的实例不保留关于其类型实参的任何信息。 其类型信息称为被擦除。例如,Foo<Bar> 与 Foo<Baz?> 的实例都会被擦除为 Foo<*>。
示例代码
package com.leofight.kotlin2
class MyStorage<out T>(private var t: T) {
fun getValue(): T {
return this.t
}
fun setValue(t: @UnsafeVariance T) {
this.t = t
}
}
fun main(args: Array<String>) {
var myStorage1: MyStorage<Int> = MyStorage(5)
val myStorage2: MyStorage<Any> = myStorage1
println(myStorage2.getValue())
myStorage2.setValue("hello")//泛型擦除
println(myStorage2.getValue())
}
泛型函数
不仅类可以有类型参数。函数也可以有。类型参数要放在函数名称之前:
fun <T> getValue(item: T): T {
return item
}
要调用泛型函数,在调用处函数名之后指定类型参数即可:
fun main(args: Array<String>) {
val item = getValue<Int>(3)
println(item)
val item2 = getValue("hello")
println(item2)
}
泛型约束
能够替换给定类型参数的所有可能类型的集合可以由泛型约束限制。
上界
最常见的约束类型是与 Java 的 extends 关键字对应的 上界:
fun <T : Comparable<T>> sort(list: List<T>) {
// ……
}
冒号之后指定的类型是上界:只有 Comparable<T> 的子类型可以替代 T。 例如:
sort(listOf(1, 2, 3)) // OK。Int 是 Comparable<Int> 的子类型
sort(listOf(HashMap<Int, String>())) // 错误:HashMap<Int, String> 不是 Comparable<HashMap<Int, String>> 的子类型
默认的上界(如果没有声明)是 Any?。在尖括号中只能指定一个上界。 如果同一类型参数需要多个上界,我们需要一个单独的 where-子句:
fun <T> copyWhenGreater(list: List<T>, threshold: T): List<String>
where T : CharSequence,
T : Comparable<T> {
return list.filter { it > threshold }.map { it.toString() }
}
网友评论