美文网首页Scala
Scala 通俗易懂 ---- 协变、逆变、不变

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

作者: 数星星的鱼 | 来源:发表于2019-11-22 14:21 被阅读0次

协变、逆变、不变

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

协变:声明时泛型是父类,赋值时泛型可以是父类也可以是子类

逆变:声明时泛型是子类,赋值时泛型可以是子类也可以是父类

不变:声明时泛型是什么类型,赋值时也只能是什么类型

示例说明

准备工作

现有类声明如下:

// Dog 类继承自 Animal 类
class Animal
class Dog extends Animal

协变

声明语法:

// 协变类型,泛型前面有一个'加号'
class MyList1[+V]

示例代码:

val list1_1: MyList1[Animal] = new MyList1[Dog]()       // 正确
val list1_2: MyList1[Animal] = new MyList1[Animal]()    // 正确
val list1_3: MyList1[Dog] = new MyList1[Animal]()       // 出错

说明:

协变类型声明时泛型是父类,赋值时泛型可以是父类,也可以是子类

逆变

声明语法:

// 逆变类型,泛型前面有一个'减号'
class MyList2[-V]

示例代码:

val list2_2: MyList2[Dog] = new MyList2[Dog]()          // 正确
val list2_3: MyList2[Dog] = new MyList2[Animal]()       // 正确
val list2_1: MyList2[Animal] = new MyList2[Dog]()       // 出错

说明:

逆变类型声明时泛型是子类,赋值时泛型可以是子类,也可以是父类

不变

声明语法:

// 不变类型,泛型前面'没有符号'
class MyList3[V]

示例代码:

val list3_2: MyList3[Dog] = new MyList3[Dog]()          // 正确
val list3_3: MyList3[Dog] = new MyList3[Animal]()       // 出错
val list3_1: MyList3[Animal] = new MyList3[Dog]()       // 出错

说明:

不变类型声明时泛型是子类,赋值时泛型只能是子类

完整代码

    // Dog 类继承自 Animal 类
    class Animal
    class Dog extends Animal

    // 声明拥有泛型的类,泛型前面有一个'加号'
    class MyList1[+V]

    // 声明拥有泛型的类,泛型前面有一个'减号'
    class MyList2[-V]

    // 声明拥有泛型的类,泛型前面'没有符号'
    class MyList3[V]

    def main(args: Array[String]): Unit = {

        // 协变类型声明时泛型是父类,赋值时泛型可以是父类,也可以是子类
        val list1_1: MyList1[Animal] = new MyList1[Dog]()       // 正确
        val list1_2: MyList1[Animal] = new MyList1[Animal]()    // 正确
        val list1_3: MyList1[Dog] = new MyList1[Animal]()       // 出错

        // 逆变类型声明时泛型是子类,赋值时泛型可以是子类,也可以是父类
        val list2_2: MyList2[Dog] = new MyList2[Dog]()          // 正确
        val list2_3: MyList2[Dog] = new MyList2[Animal]()       // 正确
        val list2_1: MyList2[Animal] = new MyList2[Dog]()       // 出错

        // 不变类型声明时泛型是子类,赋值时泛型只能是子类
        val list3_2: MyList3[Dog] = new MyList3[Dog]()          // 正确
        val list3_1: MyList3[Animal] = new MyList3[Dog]()       // 出错
        val list3_3: MyList3[Dog] = new MyList3[Animal]()       // 出错
    }

对比Java

Java 中只有不变,没有协变也没有不变,声明时泛型是什么类型,赋值时泛型也必须是什么类型

示例代码如下:

    class Animal {}

    class Dog extends Animal {}

    static class MyList<X extends Animal> {}

    public static void main(String[] args) {
        MyList<Animal> m1 = new MyList<Animal>();   // 正确
        MyList<Dog> m2 = new MyList<Dog>();         // 正确
        MyList<Animal> m3 = new MyList<Dog>();      // 错误
        MyList<Dog> m4 = new MyList<Animal>();      // 错误

    }

相关文章

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

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

  • Flow中对逆变和协变的处理

    协变逆变不变的解释 协变:f(Employee) extend f(Person) 逆变:f(Person) ...

  • kotlin 泛型

    1.协变 逆变 不变

  • Scala 类型系统(1)

    协变逆变引入原因 协变和逆变主要是用来解决参数化类型的泛化问题。我的理解是解决Scala高阶函数参数引入。 定义协...

  • java 不变、协变、逆变

    java 不变、协变、逆变 前言 先说结论,java 的 List 是不变的,java 的 array 是协变的。...

  • Scala教程之:深入理解协变和逆变

    在之前的文章中我们简单的介绍过scala中的协变和逆变,我们使用+ 来表示协变类型;使用-表示逆变类型;非转化类型...

  • JAVA泛型与类型安全

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

  • Kotlin学习笔记 - 泛型

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

  • Typescript 中的协变和逆变

    Typescript的协变和逆变和C# Scala中的类似,但是Typescript的会自动算出来接口属于协变还是...

  • Scala 泛型与补充知识

    一、泛型 1.1不变、协变、逆变 语法 说明协变:Son 是 Father 的子类,则 MyList[Son] 也...

网友评论

    本文标题:Scala 通俗易懂 ---- 协变、逆变、不变

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