kotlin 泛型

参考:

菜鸟教程

kotlin中文网

类型上边界:Any? 类型下边界:Nothing 关于星号投射,其实就是*代指了所有类型,相当于out Any? : 不能生产,只能消费

星号投射

有些时候, 你可能想表示你并不知道类型参数的任何信息, 但是仍然希望能够安全地使用它. 这里所谓"安全地使用"是指, 对泛型类型定义一个类型投射, 要求这个泛型类型的所有的实体实例, 都是这个投射的子类型。

对于这个问题, Kotlin 提供了一种语法, 称为 星号投射(star-projection):

假如类型定义为 Foo , 其中 T 是一个协变的类型参数, 上界(upper bound)为 TUpper ,Foo<> 等价于 Foo . 它表示, 当 T 未知时, 你可以安全地从 Foo<> 中 读取TUpper 类型的值.
假如类型定义为 Foo , 其中 T 是一个反向协变的类型参数, Foo<> 等价于 Foo . 它表示, 当 T 未知时, 你不能安全地向 Foo<> 写入 任何东西.
假如类型定义为 Foo , 其中 T 是一个协变的类型参数, 上界(upper bound)为 TUpper , 对于读取值的场合, Foo<*> 等价于 Foo , 对于写入值的场合, 等价于 Foo .

如果一个泛型类型中存在多个类型参数, 那么每个类型参数都可以单独的投射.
比如, 如果类型定义为interface Function<in T, out U> , 那么可以出现以下几种星号投射:

Function<*, String> , 代表 Function<in Nothing, String> ;

Function<Int, *> , 代表 Function<Int, out Any?> ;

Function<, > , 代表 Function<in Nothing, out Any?> .

注意: 星号投射与 Java 的原生类型(raw type)非常类似, 但可以安全使用

关于星号投射,其实就是*代指了所有类型,相当于Any?

class A<T>(val t: T, val t2: T, val t3: T)
class Apple(var name: String)

fun main() {
    //使用类
    val a1: A<*> = A(12, "String", Apple("苹果"))
    val a2: A<Any?> = A(12, "String", Apple("苹果"))   //和a1是一样的
    println("=========================================")

    val apple = a1.t3    //参数类型为Any
    println(apple)
    println("=========================================")

    val apple2 = apple as Apple   //强转成Apple类
    println(apple2.name)
    println("=========================================")

    //使用数组
    val list1: ArrayList<*> = arrayListOf("String", 1, 1.2f, Apple("苹果"))
//    list1.add(true)
    for (item in list1) {
        println(item)
    }
    println("===========* 等价于 out Any? 只能消费,不能生产 =================")
    val list2: ArrayList<out Any?> = arrayListOf("String", 1, 1.2f, Apple("苹果"))
//    list2.add(true)
    for (item in list2) {
        println(item)
    }
    println("=========================================")
    val list3: ArrayList<Any?> = arrayListOf("String", 1, 1.2f, Apple("苹果"))
    list3.add(false)
    for (item in list3) {
        println(item)
    }
    println("=========================================")

}

星号投影,用来表示不知道关于泛型实参的任何信息,跟Java的?问号通配符类似;

注意

MutableList<*> 和 MutableList<Any?> 不一样;
MutableList<T> 在T上是不变型的,

MutableList<Any?>包含的是任何类型的元素;
MutableList<*>是包含某种特定类型元素,但不知是哪个类型,所以不能写入;但可读取;

编译器将MutableList<*> 当做out投影的类型 MutableList<out Any?>,不能让她消费任何东西;

PECS 代表生产者-Extens,消费者-Super(Producer-Extends, Consumer-Super)。

泛型类与泛型方法对比

定义:



//定义一个【泛型类】,并定义如下两个方法
internal class TestPrint1<T> {
    fun show(t: T) {
        println(t)
    }

    fun print(t: T) {
        println(t)
    }
}


//定义一个类,并定义如下两个【泛型方法】
//泛型方法更具有扩展性。
//泛型方法可以让不同方法操作不同类型,且类型还不确定。
//与泛型类不同,泛型方法的类型参数只能在它锁修饰的泛型方法中使用。

internal class TestPrint2 {
    fun <T> show(t: T) {
        println(t)
    }

    fun <T> print(t: T) {
        println(t)
    }

    fun <U, T> sum(u: U, t: T) {
        println(u.toString() + " version is " + t)
    }
}


测试

//测试 : 泛型类
@Test
fun test8() {
    val testPrint11 = TestPrint1<Int>()
    testPrint11.print(1)
    testPrint11.show(10)

    val testPrint12 = TestPrint1<String>()
    testPrint12.print("2")
    testPrint12.print("box")
}


//测试 : 泛型方法
@Test
fun test9() {
    val testPrint2 = TestPrint2()
    testPrint2.print(1)
    testPrint2.print("2")
    testPrint2.print(false)

    testPrint2.show(10)
    testPrint2.show("15")
    testPrint2.show(true)

    testPrint2.sum(1, false)
    testPrint2.sum(true, "b")
}

对比发现:泛型方法比泛型类更具有扩展性。

泛型方法测试

   @Test
    fun test7() {
        printMsg(1, "2", false, mutableListOf(0, 1))
    }
    
    private fun <T> printMsg(vararg args: T) {
        for (t in args) {
            println("t is $t")
        }
    }

泛型接口

定义

//定义泛型接口
internal interface ShowInterface<T> {
    fun show(t: T)
}

//实现类确定了类型
/**
 * 传入泛型实参时:
 * 定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator<T>
 * 但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。
 * 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
 * 即:Generator<T>,public T next();中的的T都要替换成传入的String类型。
 */
internal class ShowClass1 : ShowInterface<String> {
    override fun show(t: String) {
        println("show:$t")
    }
}

//实现类类型不确定
/**
 * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
 * 即:class FruitGenerator<T> implements Generator<T>{
 * 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"
 */
internal class ShowClass2<T> : ShowInterface<T> {
    override fun show(t: T) {
        println("show:$t")
    }
}

测试

@Test
fun test10() {
    //确定了类型
    val showClass1 = ShowClass1()
    showClass1.show("1")//这里只能string


    //不确定类型,动态设置
    val showClass21 = ShowClass2<String>()
    showClass21.show("666")

    val showClass22 = ShowClass2<Int>()
    showClass22.show(999)
}

无界类型通配符

kotlin : * 等价于 Java : ?

      @Test
    fun test1() {
        val a1 = ArrayList<String>()
        a1.add("a")
        a1.add("b")
        a1.add("c")
        val a2 = ArrayList<Int>()
        a2.add(1)
        a2.add(2)
        a2.add(3)

//        printList1(a1)       //报错
//        printList1(a2)       //报错
        printList1(a1.toMutableList())
        printList1(a2.toMutableList())

        println("=========================")

        printList2(a1)
        printList2(a2)

        println("=========================")

        printList3(a1)
        printList3(a2)
    }

    //Any
    private fun printList1(list: MutableList<Any>) {
        val iterator = list.iterator()
        while (iterator.hasNext()) {
            println(iterator.next())
        }
    }

    //泛型方法
    private fun <T> printList2(list: MutableList<T>) {
        val iterator = list.iterator()
        while (iterator.hasNext()) {
            println(iterator.next())
        }
    }

    //占位符,也称为通配符。
    // kotlin * 表示元素类型可以匹配任意类型(java中为?)
    //"*","?"可以接收任何类型。
    //类型通配符我感觉上和泛型方法差不多,只是不用在使用前进行定义
    private fun printList3(list: ArrayList<*>) {
        val iterator = list.iterator()
        while (iterator.hasNext()) {
            println(iterator.next())
        }
    }

示例:


//定义一个Person类
open class Person(var name: String)


// 定义一个Student 并继承 Person ( name 来自person )
class Student(name: String) : Person(name)


private val personList: MutableList<Person> = mutableListOf(
    Person("pA"),
    Person("pB"),
    Person("pC")
)

private val studentList: MutableList<Student> = mutableListOf(
    Student("s1"),
    Student("s2"),
    Student("s3")
)


class TestC {

    @Test
    fun test12() {
        println("=================0")
//        printMethod0(personList)
        printMethod0(studentList)

        println("=================1")
        printMethod1(personList)
//        printMethod1(studentList)

        println("=================2")
        printMethod2(personList)
        printMethod2(studentList)

        println("=================3")
        printMethod3(personList)
        printMethod3(studentList)

        println("=================4")
        printMethod4(personList)
        printMethod4(studentList)

        println("=================5")
        printMethod5(personList)
        printMethod5(studentList)

        println("=================6")
        printMethod6(personList.toMutableList())
        printMethod6(studentList.toMutableList())
    }

    //只能打印Student
    private fun printMethod0(list: MutableList<Student>) {
        val iterator = list.iterator()
        while (iterator.hasNext()) {
            when (val next = iterator.next()) {
                //先判断子类,在判断父类(因为子类也属于父类)
                is Student -> print("s=${next.name}       ")
                is Person -> print("p=${next.name}       ")
            }
        }
        println()
    }

    //只能打印person
    private fun printMethod1(list: MutableList<Person>) {
        val iterator = list.iterator()
        while (iterator.hasNext()) {
            when (val next = iterator.next()) {
                is Student -> print("s=${next.name}       ")
                is Person -> print("p=${next.name}       ")
            }
        }
        println()
    }

    //kotlin 中 out
    //我们称? extends T 为 泛型上限定: 可以接收T和T的子类
    private fun printMethod2(list: MutableList<out Person>) {
        val iterator = list.iterator()
        while (iterator.hasNext()) {
            when (val next = iterator.next()) {
                is Student -> print("s=${next.name}       ")
                is Person -> print("p=${next.name}       ")
            }
        }
        println()
    }

    //kotlin 中 in
    //我们称? super T 为 泛型下限定: 可以接收T和T的父类
    private fun printMethod3(list: MutableList<in Student>) {
        val iterator = list.iterator()
        while (iterator.hasNext()) {
            when (val next = iterator.next()) {
                is Student -> print("s=${next.name}       ")
                is Person -> print("p=${next.name}       ")
            }
        }
        println()
    }

    //泛型<T : Person> 表示 <? extend Person> : Person及其子类
    private fun <T : Person> printMethod4(list: MutableList<T>) {
        val iterator = list.iterator()
        while (iterator.hasNext()) {
            when (val next = iterator.next()) {
                is Student -> print("s=${next.name}       ")
                is Person -> print("p=${next.name}       ")
            }
        }
        println()
    }

    //通配符
    private fun printMethod5(list: MutableList<*>) {
        val iterator = list.iterator()
        while (iterator.hasNext()) {
            when (val next = iterator.next()) {
                is Student -> print("s=${next.name}       ")
                is Person -> print("p=${next.name}       ")
            }
        }
        println()
    }

    //Any
    private fun printMethod6(list: MutableList<Any>) {
        val iterator = list.iterator()
        while (iterator.hasNext()) {
            when (val next = iterator.next()) {
                is Student -> print("s=${next.name}       ")
                is Person -> print("p=${next.name}       ")
            }
        }
        println()
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值