美文网首页
kotlin 泛型之协变(out)和逆变(in)

kotlin 泛型之协变(out)和逆变(in)

作者: Bfmall | 来源:发表于2022-11-23 17:06 被阅读0次

    一、协变(out)和逆变(in)

    /**
     * DESC   :
     * 1.泛型只读模式out
     * 2.out T协变 / in T 逆变
     */
    const val KtBaseInOrOutTest01_TAG = "KtBaseInOrOutTest01"
    
    class TestOutClass<INPUT>(private val isR: Boolean, vararg objects: INPUT) {
        //开启INPUT泛型的只读模式
        private val objArr: Array<out INPUT> = objects
    
        //5种返回类型的变化解释
        fun getR1() : Array<out INPUT> ? = objArr.takeIf { isR }
    
        //有可能是Array<out INPUT>,也可能是String, 就属于这种Serializable,用Any代替
        fun getR2() : Any = objArr.takeIf { isR } ?: "为null了"
    
        //有可能是Array<out INPUT>,也可能是String, 也可能是?  就属于这种Serializable?,用Any?代替
        fun getR3() : Any ? = objArr.takeIf { isR } ?: "为null了" ?: null
    
    
        fun getR4(index: Int) : INPUT ? = objArr[index].takeIf { isR } ?: null
    
    
        fun getR5(index: Int) : Any ? = objArr[index].takeIf { isR } ?: "AAA" ?: 666 ?: 666.6 ?: 'A' ?: false ?: null
    
        //运算符重载
        operator fun get(index:Int) : INPUT ? = objArr[index].takeIf { isR }
    
        /**
         * 泛型是很大的类型范围,可以接收很多类型,也可以接受null,但是接受null要处理好
         * String? 能够接受"hahah", 还可以接受null,所以String?比String功能要强大
         * 小结:异步处理泛型接收,都用String?处理,规范化
         */
        fun <INPUT> inputObj(input: INPUT) {
            Log.d(KtBaseInOrOutTest01_TAG, "长度为:"+((input as String?)?.length ?: "input为null"))
        }
    }
    
    //----------------------------------------------------------------------------
    
    /**
     * 生产者 out T 协变
     * out T 此泛型能够被获取 读取,所以是out
     * out T代表整个生产者类里面 这个T只能被读取,不能被修改
     */
    interface Producer<out T> {
    
        //不能被修改,编译不通过
    //    fun consumer(item: T) //消费代码
    
        //只能被读取
        fun producer() : T
    }
    
    /**
     * 消费者 in T 逆变
     * in T 此泛型只能被修改,不能读取,所以是in
     */
    interface  Consumer<in T> {
        //只能被修改了
        fun consumer(item : T) //消费代码
    
        //不能被读取,编译不通过
    //    fun producer() : T
    }
    
    /**
     * 生产者and消费者
     */
    interface ProducerAndConsumer<T> {
        fun producer() : T//生产代码
    
        fun consumer(item : T) //消费代码
    }
    
    //--------------------------------------
    
    open class Animal{}
    
    open class Human : Animal()//人类
    
    open class Man: Human()//男人
    
    open class Women : Human()//女人
    
    
    //-----------------生产者Producer start--------------------
    
    
    class ProducerClass1: Producer<Animal> {
    
        override fun producer(): Animal {
            Log.d(KtBaseInOrOutTest01_TAG, "Animal...producer==>生产动物")
            return Animal()
        }
    
    }
    
    class ProducerClass2: Producer<Human> {
    
        override fun producer(): Human {
            Log.d(KtBaseInOrOutTest01_TAG, "Human...producer==>生产人类")
            return Human()
        }
    
    }
    
    class ProducerClass3: Producer<Man> {
    
        override fun producer(): Man {
            Log.d(KtBaseInOrOutTest01_TAG, "Man...producer==>生产男人")
            return Man()
        }
    
    }
    
    class ProducerClass4: Producer<Women> {
    
        override fun producer(): Women {
            Log.d(KtBaseInOrOutTest01_TAG, "Women...producer==>生产女人")
            return Women()
        }
    
    }
    
    //-----------------生产者Producer end--------------------
    
    
    //-----------------消费者Consumer start--------------------
    class ConsumerClass1 : Consumer<Animal> {
        override fun consumer(item: Animal) {
            Log.d(KtBaseInOrOutTest01_TAG, "Animal...consumer==>消费者动物")
        }
    
    }
    
    class ConsumerClass2 : Consumer<Human> {
        override fun consumer(item: Human) {
            Log.d(KtBaseInOrOutTest01_TAG, "Animal...consumer==>消费者人类")
        }
    
    }
    class ConsumerClass3 : Consumer<Man> {
        override fun consumer(item: Man) {
            Log.d(KtBaseInOrOutTest01_TAG, "Animal...consumer==>消费者男人")
        }
    
    }
    class ConsumerClass4 : Consumer<Women> {
        override fun consumer(item: Women) {
            Log.d(KtBaseInOrOutTest01_TAG, "Animal...consumer==>消费者女人")
        }
    
    }
    
    
    //-----------------消费者Consumer end--------------------
    class KtBaseInOrOutTest01 {
    
        fun testOut01() {
            val testOutTest = TestOutClass(true, "你好", 66, 'A')
            testOutTest.inputObj("hahha")
            testOutTest.inputObj(null)
    //        testOutTest.inputObj(99)
    
            val r1 = testOutTest.getR1()
            val r2 = testOutTest.getR2()
            val r3 = testOutTest.getR3()
            val r4 = testOutTest.getR4(1)
    
            Log.d(KtBaseInOrOutTest01_TAG, "testOut01==>r1="+r1)
            Log.d(KtBaseInOrOutTest01_TAG, "testOut01==>r2="+r2)
            Log.d(KtBaseInOrOutTest01_TAG, "testOut01==>r3="+r3)
            Log.d(KtBaseInOrOutTest01_TAG, "testOut01==>r4="+r4)
    
        }
    
        /**
         * out T 协变
         *
         * 父类 = 子类(赋值给父类)
         */
        fun testInOut01() {
            //out T 协变
            /**
             * 泛型特点:
             * 1.默认情况下,泛型的子类对象  不可以赋值给 泛型的父类对象
             * 2.加上out,泛型的子类对象  就可以赋值给 泛型的父类对象
             * 3.加上out,泛型具体处的子类对象  可以赋值给  泛型声明处的父类对象
             */
            val p1 : Producer<Animal> = ProducerClass1()//ProducerClass1本来传递的就是Animal,当然可以
            val p2 : Producer<Animal> = ProducerClass2()//ProducerClass2传递Human,也可以,因为是out,去掉out就编译报错了
            val p3 : Producer<Animal> = ProducerClass3()//ProducerClass3传递Man,也可以,因为是out
            val p4 : Producer<Animal> = ProducerClass4()//ProducerClass4传递Women,也可以,因为是out
    
            val p5: Producer<Man> = ProducerClass3()//ProducerClass3传递Man,赋值给Producer<Man>类型,毫无疑问没问题,有无out都一样
    
    
            /**
             *
             * java中写法参考
                List<CharSequence> list = new ArrayList<CharSequence>();
                //父类 CharSequence, 子类String,不能将String赋值给CharSequence,编译报错
                //        List<CharSequence> list2 = new ArrayList<String>();
    
                // ? extends T就相当于kt中的out,所以才可以泛型子类对象 赋值给 泛型父类对象
                // ? extends CharSequence这样写法就不会报错了
                List<? extends CharSequence> list3 = new ArrayList<String>();
             */
        }
    
    
        /**
         * in T 逆变
         * 子类 = 父类(赋值给子类)
         */
        fun testInOut02() {
            /**
             * in T
             * 默认情况下:泛型具体处的父类对象 是不可以赋值给 泛型声明处的子类对象的
             * 加上in : 泛型具体处的父类对象 就可以赋值给 泛型声明处的子类对象了
             */
            val c1 : Consumer<Animal> = ConsumerClass1()//ConsumerClass1他本来就是传递Animal,当然可以
            //以下c2,c3,c4编译报错
    //        val c2 : Consumer<Animal> = ConsumerClass2()
    //        val c3 : Consumer<Animal> = ConsumerClass3()
    //        val c4 : Consumer<Animal> = ConsumerClass4()
    
            val c5: Consumer<Human> = ConsumerClass2()//ConsumerClass2传递Human,当然可以
            val c6: Consumer<Man> = ConsumerClass3()//ConsumerClass3传递Man,当然可以
            val c6_1 : Consumer<Man> = ConsumerClass2()//ConsumerClass2传递Human,居然也可以,因为in T
            val c7: Consumer<Women> = ConsumerClass4()//ConsumerClass4传递Women,当然可以
    
    
            /**
             * 参考java代码
                //父类 CharSequence, 子类String
                List<CharSequence> list = new ArrayList<CharSequence>();
    
                //父类CharSequence是不可以赋值给子类String的
                //        List<String> list2 = new ArrayList<CharSequence>();
    
                //使用 ? super T,相当于kt中的in,所以才可以 泛型父类具体处的对象  赋值给  泛型子类声明处的对象
                //使用in T, 泛型父类具体处的对象  可以赋值给  泛型子类声明处的对象
                List<? super String> list3 = new ArrayList<CharSequence>();
    
                //kt 逆变:子类泛型声明处对象  可以接收 父类泛型具体处对象
             */
        }
    }
    

    相关文章

      网友评论

          本文标题:kotlin 泛型之协变(out)和逆变(in)

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