美文网首页
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泛型与协变及逆变原理剖析

    1.密封类 密封类(sealed class)①密封类用来表示受限的类继承结构,对密封类中的某个值来说,它所属类型...

  • Kotlin泛型与协变及逆变剖析

    Kotlin泛型与协变及逆变剖析 关于泛型的使用其实很简单,但是!!如文章开头所说,一直理解不了在Java框架中很...

  • Kotlin学习笔记 - 泛型

    1. 基本用法 2. 型变 型变包括 协变、逆变、不变 三种: 协变:泛型类型与实参的继承关系相同 逆变:泛型类型...

  • 泛型编程中的型变

    在泛型编程中,经常会提到型变。型变分为两种:协变与逆变。协变covariant表示与泛型参数T的变化相同,而逆变c...

  • Java协变和逆变

    泛型的协变与逆变 协变与逆变用来描述类型转换(type transformation)后的继承关系,其定义如下:如...

  • Scala 通俗易懂 ---- 协变、逆变、不变

    协变、逆变、不变 Scala 语言中协变、逆变、不变是指拥有泛型的类型,在声明和赋值时的对应关系 协变:声明时泛型...

  • JAVA泛型与类型安全

    1. 基础泛型 2. 协变与逆变与不变 协变 简单来说即: Java中的数组是协变的 逆变与协变相对,逆转了类型关...

  • Scala 泛型协变与泛型边界

    代码准备 泛型协变 泛型协变、逆变、不变是指拥有泛型的类在声明和赋值时的对应关系。 协变:声明时泛型是父类,赋值时...

  • Java 泛型与通配符

    参考地址:《Java 泛型,你了解类型擦除吗?》 《Java中的逆变与协变》 《java 泛型中 T、E .....

  • 协变和逆变

    Java的泛型只有通配符?和extends、super,没有语法上的协变和逆变。 什么是协变和逆变? 在混合OO和...

网友评论

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

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