和Java的泛型相比,Koltin的泛型还是与之不同的。直达链接Java的泛型理解
泛型约束
/**
* 并不是所有的类型参数T都具有可比性,必须限定T的类型,如果只是数字类型比较可以限定Number,
* 因为Int,Double等数字类型都继承Number,是Number的子类型。声明类型参数时在T后面添加冒号:和限定类型,这种表示方式就是泛型约束。
* 泛型约束主要用于泛型函数和泛型类的声明。
*/
private fun <T: Number> isEqual(a: T,b: T): Boolean{
return (a == b)
}
/**
* 为此可以将类型参数限定为Comparable<T>接口类型,所有可以比较的对象都实现Comparable<T>接口,Comparable<T>本身也是泛型类型。
*/
fun <T : Comparable<T>> isEqua(a: T,b: T): Boolean{
return (a == b)
}
out(协变)
如果泛型类只将泛型类型作为函数的返回(输出),那么使用 out:
interface Production<out T> {
fun produce(): T
}
in(逆变)
如果泛型类只将泛型类型作为函数的入参(输入),那么使用 in:
interface Consumer<in T> {
fun consume(item: T)
}
invariant(不变)
如果泛型类既将泛型类型作为函数参数,又将泛型类型作为函数的输出,那么既不用 out 也不用 in:
interface ProductionConsumer<T> {
fun produce(): T
fun consume(item: T)
}
- out 声明我们称之为协变,就是可以兼容自己及其子类,相当于 Java 的 ? extend E
- in 声明我们称之为逆协变,就是可以兼容自己及其父类,相当于 Java 的 ? super E
为什么不直接用 Java 的声明方式?因为 Java ? extends E 和 ? super E 只能用于方法,而 in 和 out 是可以用于类和方法的
- 子类泛型对象可以赋值给父类泛型对象,用 out。
- 父类泛型对象可以赋值给子类泛型对象,用 in;
星号投影
- 星号投影用来表明“不知道关于泛型实参的任何信息”。
- 类似于 Java 中的无界类型通配符?, Kotlin 使用星号投影*。
*
代指了所有类型,相当于Any?
。
例如:MutableList<*> 表示的是 MutableList<out Any?>
fun main() {
val list1 = mutableListOf<String>()
list1.add("string1")
list1.add("string2")
printList(list1)
val list2 = mutableListOf<Int>()
list2.add(123)
list2.add(456)
printList(list2)
}
fun printList(list: MutableList<*>) {
println(list[0])
}
正是由于使用 out 修饰以及星号投影的类型不确定性,会导致写入的任何值都有可能跟原有的类型冲突。因此,星号投影不能写入,只能读取。