zoukankan      html  css  js  c++  java
  • 协变与逆变原理深度剖析及实例演示

    在上一次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。

  • 相关阅读:
    leetcode 86. Partition List
    leetcode 303. Range Sum Query
    leetcode 1310. XOR Queries of a Subarray
    leetcode 1309. Decrypt String from Alphabet to Integer Mapping
    leetcode 215. Kth Largest Element in an Array
    将numpy.ndarray写入excel
    leetcode 1021 Remove Outermost Parentheses
    leetcode 1306. Jump Game III
    leetcode 1305. All Elements in Two Binary Search Trees
    ICCV2019 oral:Wavelet Domain Style Transfer for an Effective Perception-distortion Tradeoff in Single Image Super-Resolution
  • 原文地址:https://www.cnblogs.com/webor2006/p/11291744.html
Copyright © 2011-2022 走看看