美文网首页
Kotlin进阶 - 泛型

Kotlin进阶 - 泛型

作者: 海_3efc | 来源:发表于2021-07-20 11:12 被阅读0次

在Android开发中我们经常用到泛型,如:List、Map、Set、Adapter等,那么在Kotlin中同样支持泛型。
什么是泛型呢?
泛型:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型。

一、Kotlin中定义泛型方式

在Kotlin中定义泛型有跟Java一样,有以下两种方式:

  • 定义在类上
  • 定义在函数中
    定义在类上示例:
class MagicBox<T>(val item: T) {
    var available = false

    fun fetch(): T? {
        return item.takeIf { available }
    }
}

定义在函数中

class MagicBox<T>(val item: T) {
    var available = false

    /**
     * 函数中增加范式类型,类似Java
     */
    fun <R> fetch(anotherGenericity: (T) -> R): R? {
        return anotherGenericity(item).takeIf { available }
    }
}

二、Kotlin中定义约束泛型

Kotlin中定义约束泛型与Java < T extend XXX>定义泛型的方式类似,表示泛型指定的类型必须为指定类型的类或继承了指定类型类的子类。这句话有点绕,举个例子:定义一泛型class A<T : B>(),传入的泛型T必须为B或者B的子类。完整示例如下:

//定义一个约束泛型
private class ConstraintMagicBox<T:Human>(item:T){

}

//定义一个父类
private open class Human(val name: String,val age:Int)
//定义一个Human类的子类
private class Male(name: String,age: Int):Human(name, age)
//定义一个Human类的子类
private class Female(name: String,age: Int):Human(name, age)

fun main() {
    //同为Human类型的可传入
    val male = ConstraintMagicBox(Male("Jack", 20))
    val female = ConstraintMagicBox(Female("Jim", 20))
}

三、Kotlin定义数量可变参数泛型

这点类似Java中给方法定义可变参数(private void method(int.. num)),在Kotlin中定义方式要借助关键字vararg,普通函数和构造函数均可使用。
示例如下:

private class VarMagicBox<T : VarHuman>(vararg val items: T) {

    //根据参数从items中获取数据,其中items类型未Array
    fun fetch(index: Int): T? {
        return items.getOrNull(0)
    }

    //在函数中增加可变参数
    fun fetch(vararg indexs: Int):List<T>{
        indexs.takeIf {
            indexs.isNotEmpty()
        }.run {
            return items.filterIndexed { index, t ->
                indexs.contains(index)
            }
        }
    }
}

private open class VarHuman(val name: String, val age: Int)

四、Kotlin中用in、out修饰泛型

在Java中在定义一个List中,指定一个特定类型,创建实例时只能new该类型的实例,无法new出子类或者父类的实例,
例子:
ArrayList<String> list = new ArrayList<CharSequence>()
或者
ArrayList<CharSequence> list = new ArrayList<String>()
这两种写法在JAVA是不支持的,正确的写法为:ArrayList<String> list = new ArrayList<String>()
但是在Kotlin中可以做到支持
当然针对上面定义的泛型例子同样不支持,那么Kotlin如何才能支持这样的写法呢?
因为Kotlin中有两个重要的关键字in(协变)out(逆变)
下面我们就来看下者两个关键字如何做到支持上述写法的。
用法非常简单,先上示例,看下使用方式:

//out修饰的泛型 仅将泛型作为函数返回值
//作用:让子类泛型对象可以赋值给父类泛型对象
interface OutTest<out T>{
    fun outTest():T
}

//in修饰的泛型 仅将泛型作为函数参数,泛型无法当做返回值
//作用:让父类泛型对象可以赋值给子类泛型对象
interface InTest<in T>{
    fun inTest(param : T)
}

测试代码如下:

open class Food()
open class FastFood():Food()
class Hamburg():FastFood()

class FastFoodStore() : OutTest<FastFood>{
    override fun outTest(): FastFood {
        println("FastFoodStore ----------")
        return FastFood()
    }
}

class HamburgStore():InTest<FastFood>{
    override fun inTest(param: FastFood) {
        println("HamburgStore-----------")
    }
}

fun main() {
    //子类对象可以传给父类泛型对象 out
    val food1 : OutTest<Food> = FastFoodStore()

    //父类对象可以传给子类泛型对象 in
    val food2 : InTest<Hamburg> = HamburgStore()
}

关键字in、out使用总结
主要有两点:

  • out修饰的泛型只能在函数返回值中使用,in修饰的泛型只能在函数的参数中使用;
  • out修饰的泛型只能将子类泛型对象赋值给父类泛型对象in修饰的泛型只能将父类泛型对象赋值给子类泛型对象,如下图示;
    image.png

欢迎留言大家互相交流学习!


示例源码地址kotlin_demo

相关文章

  • Kotlin 进阶之路7 接口、泛型与扩展

    Kotlin 进阶之路 目录 1.接口 2.泛型 3.扩展

  • Kotlin进阶 - 泛型

    在Android开发中我们经常用到泛型,如:List、Map、Set、Adapter等,那么在Kotlin中同样支...

  • 泛型

    与Java泛型相同,Kotlin同样提供了泛型支持。对于简单的泛型类、泛型函数的定义,Kotlin 与 Java ...

  • Kotlin---泛型

    Kotlin不变型泛型 Kotlin的不变型泛型和Java一样,通过声明泛型类型来使用泛型类。而该种泛型声明后,则...

  • Kotlin 泛型 VS Java 泛型

    建议先阅读我的上一篇文章 -- Java 泛型 和 Java 泛型一样,Kotlin 泛型也是 Kotlin 语言...

  • Kotlin for android学习六:泛型

    前言 kotlin官网和kotlin教程学习教程的笔记。 1. 声明泛型 2. 泛型约束 : 对泛型的类型上限进行...

  • 泛型

    Kotlin 泛型详解 声明一个泛型类 声明一个泛型方法 泛型约束 List 和 List 是...

  • Kotlin 泛型

    Kotlin 支持泛型, 语法和 Java 类似。例如,泛型类: 泛型函数: 类型变异 Java 的泛型中,最难理...

  • Kotlin:泛型杂谈(下)

    在Kotlin:泛型杂谈(上)中,从泛型扩展属性、非空约束、实例化类型参数三个方面简单介绍了一下Kotlin中泛型...

  • 【Android】 Kotlin(七)泛型

    深入理解Kotlin泛型 Kotlin 的泛型与 Java 一样,都是一种语法糖,即只在源代码中有泛型定义,到了c...

网友评论

      本文标题:Kotlin进阶 - 泛型

      本文链接:https://www.haomeiwen.com/subject/cvjlmltx.html