Kotlin-泛型基础知识

Kotlin-泛型基础知识

概念:泛型是一种类型参数化的机制,允许我们编写具有通用性的代码。
        Kotlin 中的泛型使用尖括号 < > 来定义,可以用在类,接口,方法上。

1. 声明泛型类型
在 Kotlin 中,可以在类、接口、函数等处声明泛型。泛型类型使用尖括号 < > 来声明,例如:
class Box<T>(var value: T)


2. 使用泛型
使用泛型类时,你需要指定具体的类型:
val intBox = Box<Int>(10)
val stringBox = Box("Hello")

3. 泛型函数
你也可以为函数声明泛型:
fun <T> printElement(element: T) {
    println(element)
}

4. 泛型约束
有时你可能想要限制泛型的类型,例如,只允许传入数字类型。在 Kotlin 中,你可以使用 : Type 来约束类型参数:
fun <T : Number> printNumber(number: T) {
    println(number)
}

5、协变(Covariance)表示输出、生产、获取,使用 out 关键字。
协变允许你将一个类型视为另一个类型的子类型。换句话说,如果一个类型A是类型B的子类型,那么类型A的协变泛型可以安全地被视为类型B的泛型。在Kotlin中,协变通过在泛型声明中使用out关键字来实现。
Kotlin 中的 <out T> 类似于 Java 中的 <? extends T>。

6、逆变(Contravariance)表示输入、消费、传递,使用 in 关键字
逆变与协变相反,它允许你将一个类型视为另一个类型的超类型。在Kotlin中,逆变通过在泛型声明中使用in关键字来实现。
Kotlin 中的 <in T> 类似于 Java 中的 <? super T>。

                                        Kotlin                            Java                            边界
协变(out)        List<out TextView>         List<? extends TextView>     上限
逆变(in)          List<in TextView>            List<? super TextView>         下限

7. 使用星号投影(Wildcard projections)处理不确定的泛型类型
有时你可能需要处理不确定的泛型类型,可以使用星号投影(例如 List<*>):
fun processList(list: List<*>) { // 处理任何类型的列表
    // 注意:不能安全地访问元素,因为类型未知
}

例子:

class TestGeneric3 {

    @Test
    fun testGeneric3(){
        //基础泛型
        //test1()
        //逆变
        //test2()
        //协变
        //test3()
        //通配符*
        //test4()
        //通配符
        test5()
    }

    /**
     * 基础泛型
     */
    private fun test1(){
        var box1 = Box1(1)
        var box11 = Box1("abc")
        println("test1 : ${box1.getItem()} ,  ${box11.getItem()}")

        var box2 = Box2("kotlin", 8)
        println("test2 : ${box2.getParam1()}, ${box2.getParam2()}")

        println("convertToInt : " + convertToInt(33.83))
    }

    /**
     * 在使用泛型时,可以限制类型参数的上界。这可以通过使用冒号 : 加上类型约束来实现。例如,我们可以指定一个类型参数必须是某个类的子类,或者实现了某个接口。下面是一个使用类型约束的例子:
     */
    private fun <T : Number> convertToInt(value : T) : Int{
        return value.toInt()
    }

    /**
     * 测试in:逆变
     */
    private fun test2(){
        var list = ArrayList<MyComparable<in String>>()
        var myComparable = object : MyComparable<String>{
            override fun myCompare(param: String): Int {
                return param.toInt()
            }
        }
        list.add(myComparable)

        var myComparable2 = object : MyComparable<String>{
            override fun myCompare(param: String): Int {
                return param.toInt()
            }
        }
        list.add(myComparable2)
        test2Print(list)
    }

    /**
     * in:逆变
     */
    private fun test2Print(list : List<MyComparable<in String>>){
        list.forEachIndexed { index, myComparable ->
            println("in逆变:index : ${index} ,  value : ${myComparable.myCompare("123${index}")}")
        }
    }

    private fun test3(){
        var myOut1 = testMyOut1()
        var myOut2 = testMyOut2()
        println("测试协变:${myOut1.myOut()} , ${myOut2.myOut()}")
    }

    private fun testMyOut1() : MyOut<out String>{
        var myOut1 = object : MyOut<String>{
            override fun myOut(): String {
                return "协变1"
            }
        }
        return myOut1
    }

    private fun testMyOut2() : MyOut<out Int>{
        var myOut2 = object : MyOut<Int>{
            override fun myOut(): Int {
                return 666
            }
        }
        return myOut2
    }

    private fun test4(){
        var list = ArrayList<Int>()
        list.add(2)
        list.add(8)
        list.add(3)

        var list2 = ArrayList<String>()
        list2.add("test66")
        list2.add("test88")

        test4Print(list)
        test4Print(list2)
    }
    /**
     * 通配符*
     */
    private fun test4Print(list : ArrayList<*>){
        list.forEachIndexed { index, any ->
            println("test4 通配符:${index} , ${any}")
        }
    }

    private fun test5(){
        var list = ArrayList<Int>()
        list.add(3)
        list.add(5)
        list.add(8)
        test5Print(list)
    }

    /**
     * 通配符 - 只能是Number类型, 不能是字符串
     * 使用关键字 out 来支持协变,等同于 Java 中的上界通配符 ? extends。
     * 使用关键字 in 来支持逆变,等同于 Java 中的下界通配符 ? super。
     */
    private fun test5Print(list : ArrayList<out Number>){
        list.forEachIndexed { index, number ->
            println("通配符:${index}, ${number}")
        }
    }

}


//<T> 表示泛型类型参数,并且 T 是一个类型参数,编译器会根据实参的类型推断出 T 的具体类型
class Box1<T>(private val item : T){

    //泛型函数返回类型为T
    fun getItem() : T{
        return item
    }
}

//支持多个类型参数的泛型定义
class Box2<T, R>(private val param1 : T, private val param2 : R){

    fun getParam1() : T{
        return param1
    }

    fun getParam2() : R{
        return param2
    }

}

//逆变:使用 in 修饰符声明的类型参数只能用作输入(即参数类型),不能用作输出(即返回类型)。它允许我们使用指定的类型参数的超类作为泛型类型的实参
interface MyComparable<in T> {
    fun myCompare(param : T) : Int
}

//协变:使用 out 修饰符声明的类型参数只能用作输出(即返回类型),不能用作输入(即参数类型)。它允许我们使用指定的类型参数的子类作为泛型类型的实参。在函数中,协变类型参数只能作为方法的返回类型。
interface MyOut<out T>{
    fun myOut() : T
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王宁-Android

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值