kotlin学习(八)

泛型

和Java不同,kotlin要求类型实参要么被显式的说明,要么能够被编译器推导出来
一.泛型类型参数

fun <T> List<T>.slice(indices : IntRange) : List<T>{
    //some code
}

可以使用同样的语法声明泛型类的拓展属性上,但是普通属性是不能声明的。

val <T> List<T>.p : T
	get() = this.get[size - 2]
val <T> x : T = some()//错误

类型参数约束可以限制作为泛型类和泛型函数的类型实参的类型。
如果把一个类型指定为泛型类型形参的上界约束,在泛型类型具体的初始化中,其对应的类型实参就必须是这个具体类型或者它的子类型。

fun <T : Number> List<T>.sum() : T//类比于Java中T extends Number

当一个参数需要有多个约束时,其语法稍微有些不同

fun <T> getTwoGeneric(t : T) where T : CharSequence, T : Appendable{
    if (!t.endsWith('.'))
        t.append('.')
}//通过where关键字

类比于Java中默认上界Object,没有指定上界的类型形参将会使用Any?这个默认的上界

二.运行时泛型:擦除和实化类型参数
内联函数的类型形参能够被实化,意味着可以在运行时引用实际的类型实参。
通过inline关键字并且用reified标记类型参数来实现实化参数。

inline fun <reified T> isA(t : Any) = t is T

编译器把实现内联函数的字节码插入到每一次调用发生的地方。每次你调用带实化参数类型的函数时,编译器都知道这次特定调用中用作类型实参的确切类型。因此,编译器可以生成引用作为类型实参的具体类的字节码。
<注>带reified类型参数的inline函数无法在Java中调用

三.变型:泛型和子类型化
子类型:任何时候如果需要的是类型A的值,你都能够使用B类型的值当做A,那么B就称为A的子类型。
超类型:如果B是A的子类型,那么A就是B的超类型。
只有值的类型是变量类型的子类型时,才允许变量存储该值。
一个非空类型是它的可空版本的子类型么,但是它们都对应同一个类。

协变:假设存在一个泛型类Producer,如果A是B的子类型,那么Producer< A>就是Producer< B>的子类型,子类型化被保留了。

interface Producer<out T>{
	fun produce() : T
}

将一个类的类型参数标记为协变的,在该类型实参没有精确匹配到函数中定义的类型形参时,可以让该类的值作为这些函数的实参传递,也可以作为这些函数的返回值。
对于类型参数,如果把T当做返回值,则其在out位置;如果把T作为函数参数类型,则其在in位置。
类的参数类型前面的out关键字要求所有使用T的方法只能把T放在out位置而不能放在in位置。

class Group<out T : People>{
	val size : Int get() = ..
	operator fun get(i : Int) : T {...}//只在返回值使用到了T,因此是协变的
}

编译器强制实施了这种限制。
in/out规则只针对类外部可见,即除了private以外。私有方法的参数既不在in位置上也不在out位置上。

逆变:它的子类型化关系与用于类型实参的类的子类型化关系是相反的。

interface Comparator<in T>{
	fun compare(e1 : T, e2 : T) : Int{...}
}

如果B是A的子类型,那么Comparator< A>就是Comparator< B>的子类型。
in关键字的意思是,对应类型的值是传递进来给这个类方法的,并且被这些方法消费。和协变的情况类似,约束类型参数的使用将导致特定的子类型化关系。

当函数的实现调用了那些类型参数只出现在out或者in位置的方法时,可以在函数定义中给特定用途的类型参数加上变量修饰符

fun <T> copyList(source : MutableList<out T>, des : MutableList<T>){...}//source无法调用在in位置使用T参数的方法!
当然,可以直接使用List参数(因为Kotlin中的List只提供get类方法)

这一切被称为类型投影。
kotlin中的 MutableList< out T>就对应Java中的MutableList< ? extends T>
kotlin中的 MutableList< in T>就对应Java中的MutableList< ? super T>

星号投影,用来表明不知道关于泛型实参的任何信息。
< Any?>表明的是包含任意的元素,< *>表明的是包含某种特定类型元素的列表,只是不知道具体类型。
该语法对应Java中的?通配符。
当类型参数信息不重要时,可以使用星号投影的语法:不需要任何在签名中引用类型参数的方法,或者只是读取数据而不关心它的具体类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值