Kotlin系列之泛型以及与Java中泛型的区别

        Kotlin 中也有泛型的概念,和 Java 中的类似,但又不尽相同,所以可以通过下面的几个方面去看一下:

一、Kotlin中的泛形

        Kotlin 泛型的本质也是参数化类型,并且提供了编译时强类型检查,实际上也是伪泛型,和 Java 泛型类型一样。

泛形类

class Test<T>(t: T) {
    var value = t
}

泛型接口

interface IAnimal<T> {
    fun <T> test()
}

泛型方法

fun <T> initAnimal(param: T) {
    var value = param
}

二、Kotlin泛形与Java区别

        Kotlin泛型与Java泛型大部分都是相同的,但是语言特性导致有部分差异。

Java泛型不可调用泛型的方法,Kotlin可以

// Java语法不可以直接调用泛型T的方法
private <T> void fill(ArrayList<T> numbers) {
}
// Kotlin通过内联机制,可以使用泛型T的方法
inline fun <reified T> printGenerality(data: T) {  
}

        原因分析:泛型只在编译期间有效,运行期间会被擦除,所以泛型信息会消失,Java基于栈的形式调用方法得不到泛型的具体类型,Kotlin通过内联机制,编译期间是把方法直接添加到了对应的代码中,不存在栈调用的问题,所以可以通过上下文推导出泛型的具体类型。
        友情提示:内联方法慎用return,会导致调用方直接返回

通配符与协变型变

在 Kotlin 中
        上边界通配符: out 相当于 <? extends T> 适用于生产者也就是用来读取的对象

//Java : <? extends T>
Anmal<? extends dog> dog
//Kotlin : out
Anmal<out dog> dog

        下边界通配符in 相当于 <? super T> 适用于消费之也就是用来写入的对象

//Java : <? super T>
Anmal<? super world> world
//Kotlin : out
Anmal<in world> world

除了写法上的区别它还有功能上的区别
使用处型变
        在 Java 中,上下界通配符只能用在参数、属性、变量或者返回值中,不能在泛型声明处使用,所以才叫做使用处型变。
        在Kotlin中java这种使用处型变被叫做类型投影
声明处型变
        但不同的是,Kotlin 还提供 Java 所不具备的声明处型变。
        顾名思义,Kotlin 提供的 out 和 in 两个型变关键字还可以用于泛型声明的时候。

public interface Collection<out E> : Iterable<E> {
    ...
}

// 错误,这里只能用val,不能用var
class Source<out T>(var t: T) {
    ...
}

        在声明处设置 out 后,使得了在 Kotlin 中,Collection 安全的作为 Collection 的父类使用,但 E 被标记为 out 后,E只能被输出而不能写入。

interface Comparable<in T> {
    operator fun compareTo(other: T): Int
}
fun demo(x: Comparable<Number>) {
    x.compareTo(1.0) // 1.0 拥有类型 Double,它是 Number 的子类型
    // 因此,我们可以将 x 赋给类型为 Comparable <Double> 的变量
    val y: Comparable<Double> = x
}

        Comparable 在声明处设置 in 后,x 就可以和 Number 或它的子类进行比较了。

星投影

        当我们不知道泛型参数的类型信息时,但仍需要安全的使用它时,可以使用星投影,用星号*表示,星投影和 Java 中的原始类型很像,但星投影是安全。

val array1: Array<B> = arrayOf(B(), B(), B())
val array2: Array<*> = array1

        使用星投影,我们可以将array1赋值给array2,但由于此时array2并不知道泛型参数的类型,所以不能对array2进行数据写入的操作,但可以从中读取数据:

array2[0] =A() //编译器会报错
val a = array2[0] // 正常

        可以看出,星投影更适合那些泛型参数的类型不重要的场景
可以用下面官方说法理解一下

Function<*, String> 表示 Function<in Nothing, String>;
Function<Int, *> 表示 Function<Int, out Any?>;
Function<*, *> 表示 Function<in Nothing, out Any?>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值