美文网首页
12.Kotlin泛型与协变及逆变原理剖析

12.Kotlin泛型与协变及逆变原理剖析

作者: leofight | 来源:发表于2017-12-24 20:46 被阅读0次

    1.密封类

    密封类(sealed class)
    ①密封类用来表示受限的类继承结构,对密封类中的某个值来说,它所属类型只能是受限的类型之一,不能是其他类型。
    ②在某种意义上,他们是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。
    ③要声明一个密封类,需要在类名前面添加 sealed 修饰符。虽然密封类也可以有子类,但是所有子类都必须在与密封类自身相同的文件中声明。(在 Kotlin 1.1 之前,该规则更加严格:子类必须嵌套在密封类声明的内部)。
    ④密封类本身是一个抽象的类,因此它是不能被直接实例化的,而密封类本身里面可以包含一些抽象的成员的,同时密封类不允许提供
    非私有的构造方法。换句话说,密封类构造方法默认情况下是私有的。

    使用密封类的关键好处在于使用 when 表达式 的时候,如果能够验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了。

    • 示例代码
    sealed class Calculator
    
    class Add : Calculator()
    
    class Subtract : Calculator()
    
    class Multiply : Calculator()
    
    fun calculate(a: Int, b: Int, cal: Calculator) = when (cal) {
        is Add -> a + b
        is Subtract -> a - b
        is Multiply -> a * b
    }
    
    fun main(args: Array<String>) {
        println(calculate(1, 2, Add()))
        println(calculate(1, 2, Subtract()))
        println(calculate(1, 2, Multiply()))
    }
    
    
    • 运行结果
    3
    -1
    2
    

    2.Kotlin泛型

    泛型(generics),表示变量类型的参数化

    • 示例代码
    class MyGenerics<T>(t: T){
        var variable: T
    
        init {
            this.variable = t
        }
    }
    
    fun main(args: Array<String>) {
        //var myGeneric:MyGenerics<String> = MyGenerics<String>("helloworld")//完整写法
        var myGeneric = MyGenerics("helloworld")//借助于kotlin的类型推断
        println(myGeneric.variable)
    }
    
    • 运行结果
    helloworld
    

    3.协变(convariant)与逆变(controvariant)

    • 关于协变与逆变的概念及来源
       //例如List<Object>与 List<String>
    
        List<String> list = new ArrayList();
        List<Object> list2 = list;//编译失败,List<String> 并不是 List<Object> 的子类型。
    
        list2.add(new Date())
    
        String str = list.get(0)//ClassCastException:类型转换错误
    
        List<? extends Object> list ... //可以放Object类型及子类型
    
    
      //例如Collection 接口中的 addAll()方法
        //直观理解
        interface Collection<E>{
            void addAll(Collection<E> items)
        }
    
    
        void copyAll(Collection<Object to,Collection<String> from){
            to.addAll(from);//编译失败,Collection<String> 不是 Collection<Object> 的子类型
        }
    
      //实际情况
        interface Collection<E>{
            void addAll(Collection<? extends E> items;
        }
    
        Collection<String>就是Collection<? extends Obejct>的子类型 //协变
    
        List<? super String> //逆变
    
        我们如果只从中读取数据,而不往里面写入内容,那么这样的对象叫做生产者(协变);如果只向里面写入数据,而不从中读取数据,那么这样的数据叫做消费者。(逆变)
    
        生产者使用 ? extends E; 消费者使用? super E
      
    
    
    • 示例代码
    class MyClass<out T,in M>(t: T,m: M){
        private var t: T
        private var m: M
    
        init {
            this.t = t
            this.m = m
        }
    
        fun get(): T = this.t
    
        fun set(m: M){
            this.m = m
        }
    
    }
    
    fun myTest(myClass: MyClass<String,Number>){
        var myObject: MyClass<Any,Int> = myClass
        println(myObject.get())
    
    }
    
    fun main(args: Array<String>) {
        var myClass = MyClass<String,Number>("abc",2);
        myTest(myClass)
    
    
    }
    
    • 运行结果
    abc
    

    kotlin中针对协变与逆变提供了两个关键字out与in。

    相关文章

      网友评论

          本文标题:12.Kotlin泛型与协变及逆变原理剖析

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