一、泛型及泛型约束
kotlin中的泛型,和java中思维大体是相同的,但又有些区别
class Data(val t:T)//泛型类
fun play(i:Int){ //泛型方法
println(i)
}
interface onclick{ //泛型接口
fun click(t:T)
}
val data = Data("hello")//类实现
val p = play(1) //方法实现
class Data(val t:T):onclick{ //接口实现
override fun click(t: T) {
println(t)
}
}
//泛型约束 <占位符:类型>
fun play(vararg param: T):Double{
return param.sumByDouble { it.toDouble() }
}
//多个约束,T有多个上限 , where T:类型,T:类型
fun getBetterBig(list:Array,threhold:T):List where T:Number,T:Comparable{
return list.filter { it>= threhold }.sorted()
}
用法和java没什么两样。。。
二、泛型协变
再看一个例子,三个简单的继承类
open class C(open val name:String)
open class Java(override val name: String):C("java")
class Kotlin(override val name: String):Java("kotlin")
main
fun main(args: Array) {
val c = C("c")
var cList:ArrayList = arrayListOf(c)
val java = Java("java")
var javaList:ArrayList = arrayListOf(java)
val kotlin = Kotlin("kotlin")
var kotlinList:ArrayList = arrayListOf(kotlin)
for ((index,value) in cList.withIndex()) {
println("$index - ${value.name}")
}
for ((index,value) in javaList.withIndex()) {
println("$index - ${value.name}")
}
for ((index,value) in kotlinList.withIndex()) {
println("$index - ${value.name}")
}
}
打印结果
0 - c
0 - java
0 - kotlin
以上有3个ArrayList,类型分别是
每个list里放进了一个同类型的实例
结果没有任何问题
下面我们改一下代码
cList = javaList
马上编译报错
**
意思说虽然java是c的子类,但是ArrayList
所以编译不能通过
**
java中用 ArrayList extends C>可以解决这个问题
在kotlin中要这么写
val c = C("c")
var cList:ArrayList = arrayListOf(c) //
val java = Java("java")
var javaList:ArrayList = arrayListOf(java)
cList = javaList
for ((index,value) in cList.withIndex()) {
println("$index - ${value.name}")
}
打印结果
0 - java
这个时候,编译通过
其实这个写法和java的ArrayList extends C> 一模一样
来再改一下代码
val java = Java("java")
var javaList:ArrayList = arrayListOf(java)
val kotlin = Kotlin("kotlin")
var kotlinList:ArrayList = arrayListOf(kotlin)
kotlinList = javaList //这次把javaList给装有子类的kotlinList
同样出错了
**
同样提示说需要 ArrayList
所以编译不能通过
**
再次改代码去应对
val java = Java("java")
var javaList:ArrayList = arrayListOf(java)
val kotlin = Kotlin("kotlin")
var kotlinList:ArrayList = arrayListOf(kotlin) //
kotlinList = javaList
for ((index,value) in kotlinList.withIndex()) {
println("$index - ${value.name}")
}
打印结果
0 - java
同理
kotlinList也能接受cList,因为C是Kotlin的超类
kotlinList = cList
打印结果
0 - c
这下可以赋值了,打印出来的结果是java,说明kotlinList里装了java的实例
其实这个写法和java的ArrayList super Kotlin> 一模一样
接下来要引用官文的两个概念了:生产和消费
interface Source{
fun 生产():T // 只能返回T,不能将T作为参数传入
fun 消费(r:R) // 只能将R作为参数传入,不可返回R
}
生产 out -> 只出参
消费 in -> 只入参
作为
还用上面的例子
val c = C("c")
var cList:ArrayList = arrayListOf(c)
val java = Java("java")
var javaList:ArrayList = arrayListOf(java)
cList.add(java) //set
cList[0].name //get
编译通过
将cList改成
val c = C("c")
var cList:ArrayList = arrayListOf(c) //
val java = Java("java")
var javaList:ArrayList = arrayListOf(java)
cList.add(java) //set 编译出错
cList[0].name //get
prohibits(禁止) use of public open fun add(element:E) !
也就是说
接下来我们把
val c = C("c")
var cList:ArrayList = arrayListOf(c) //
val java = Java("java")
var javaList:ArrayList = arrayListOf(java)
cList.add(java) //set
cList[0].name //get 编译出错
这个错误提示很少啊?为什么不是 prohibits use of ...?
其实这个错误并不是说
三、星投影
但是如果我不知道类型该如何声明啊?
java中
private List list = new ArrayList();
在Kotlin中我也这么写
kotlin中
var list:ArrayList = ArrayList()
又是报错
晕
Kotlin中必须这样写
var list:ArrayList<*> = arrayListOf(1) //<*>必不可少 相当于java的无泛型
当 cList:ArrayList<*> = javaList 时<*>相当于
当 javaList:ArrayList<*> = cList 时<*>相当于
四、本章小节:
1、 Kotlin的泛型使用基本和Java一致
2、 Java的 extends T> 相当于 Kotlin的 ,Java的 super T> 相当于 Kotlin的
3、 只能生产(出参), 只能消费(入参)
4、 只能生产的原因是编译器无法确认什么对象符合那个未知的 T 的子类型,只知道一定返回T, 只能消费的原因是无法确认T超类的具体类型
5、<*>
相当于java中的无泛型。对于 Foo ,其中 T 是一个具有上界的协变类型参数,Foo <*>
等价于 Foo ;对于 Foo ,其中 T 是一个逆变类型参数,Foo <*>
等价于 Foo
Foo <*>
等价于 Foo Foo <*>
等价于 Foo