• 协变与逆变原理深度剖析及实例演示


    在上一次https://www.cnblogs.com/webor2006/p/11279692.html中对于泛型中的协变与逆变进行了初步了解,由于这个概念是脱离开语言而且又非常之重要的,所以接下来继续对这个概念进行进一步巩固,达到一种通透领悟的境界。

    这里还是从Java的角度再来看一下关于泛型协变与逆变的一个演变过程:

    其错误提示为:

    因为List<String>并不是List<Object>的子类型,为啥呢?这里可以采用假设法,假设这句赋值语句代码是成立的,那可以这样写:

    而由于list2是指向了list,那么可以这样写:

    很显然Object是不可能是String类型,在木有强制类型转换的情况下,所以说我们的这个假设是行不通的。

    好,下面定义几个类来演示协变与逆变的情况,先定义三个类:一个父类,两个子类:

    因为animals里面的元素接收的是Animal的子类型,当然满足要求。那接下来再来看一句代码:

    看结果:

    看一下错误提示:

    为啥?还是采用假设法,假设此句代码是成立的,那会产生啥问题呢?由于animals里面的元素类型是Animal以及它的子类型,也就是有可能是Cat,也有可能是Dog,那我们在取元素时就会出现混乱,也就说明对于协变而言,只能对它进行读,不能进行写。

    这里有一个术语:PECS:Producer Extends,Consumer Super。表示用于返回数据的生产者需要用Extends,而用于写入数据的消费者要用Super

    下面来看一下逆变的情况:

    逆变只能写,不能读,所以咱们可以往里写元素:

    接下来试着取一下元素:

    因为元素的类型是Animal及它以上的,所以从集合中拿的话很显然不一定就是Animal,那既然它里面是Animal之上的类型,是不是可以添加一个Object类型呢,试试:

    不行的,Object因为不是Animal类型,所以没法往里写,既使层次体系满足Animal之上,如果改成这样写就成:

    其实在Java中的数组是天然支持协变的,如何理解?下面看一下:

    但是!!其实是会产生问题的,如下:

    编译运行:

    以上是关于Java层面关于泛型的协变和逆变的表现,下面则回到Kotlin来看下:

    接下来来看下协变:

    上面的代码其实相当于这两行代码:

    好,接下来再来看一下逆变:

    其实相当于Java的这段代码:

    所以在Kotlin中:Consumer需要用in,而Producer需要用out。

  • 相关阅读:
    实验四 Linux系统搭建C语言编程环境
    实验三 Linux系统用户管理及VIM配置
    实验二 Linux系统简单文件操作命令
    《Linux命令行与shell脚本编程大全》勘错
    考研英语每天一段阅读理解
    仓储管理系统500bug记录一下mysql 8小时超时解决办法
    win7 64位4GB内存下 tomcat7扩大内存
    解决远程连接mysql错误1130代码的方法
    win7 64 位 tomcat 定时重启脚本
    通过Navicat for MySQL远程连接的时候报错mysql 1130
  • 原文地址:https://www.cnblogs.com/webor2006/p/11291744.html
Copyright © 2020-2023  润新知