逆变和协变在存在于强类型语言中,尽管非常少提及。可是里面蕴含了面向对象的世界观。感谢和我一起讨论这个问题的人。

这里用了C#、Scala的语法作为演示样例。事实上逆变和协变的概念跟语言本身关系不大。事实也是如此。

一、定义

逆变的參数能够由指定的类型的子类型取代,协变的參数能够由指定类型的父类型取代。

Scala中的逆变声明:Function[-A,+B] ;当中泛型-A为逆变类型,在实例化时,能够使用A类型或者A类的子类型。

二、协变与逆变的用途不同

1.语义

Scala中,函数的原型之中的一个包括Function1[-A,+B]。表示一个A类型的输入,B类型的输出(返回)。替换的语法为A=>B

这个函数的定义就好像说。我须要类A帮我做一些事情,处理完之后给你一个B。而A能够完毕的工作。其子类也应该能够完毕,这正是里氏替换原则——父类出现的地方都能够用子类取代。

逆变强调功能——“能做什么”。

顺便看下协变。输出为协变,表示我会给你你个B对象,假设B是肉,我当然能够说给了你食物,而食物是肉的父类,恰好是协变。假设使用逆变则说不通。

协变强调类型——“是什么”。

2.刀和肉的样例

类型:食品<-肉<-牛肉。武器<-刀<-牛肉刀。(<-表示继承关系:父类<-子类)

情景:继续拿Function1做演示样例。假设Function1须要一把刀。会生产出肉。大致为Function(A):B普通刀(刀类)会生产出普通肉(肉类),牛肉刀会生产出牛肉。

问题:A的类型?B的类型?怎样确定

A的类型可以为刀和牛肉刀,由于牛肉刀也是刀。

甚至说刀的子类都可以满足条件——都有刀的功能。从继承来讲刀的子类都是刀。

所以A的类型应该为逆变——-刀(刀和子类)

由于做出的是肉,所以B类型肯定包括肉,但不确定是牛肉。所以我们能够设定返回为肉类型。

对于这个情景,我们对FunctionX的终于定义为:FunctionX(-刀):肉

没有协变?

我们没有看到协变,实际上在C#和Scala中。我们设定一个食品类型  来接收FunctionX的返回值也不会报错。由于全部的返回类型在语言中都被声明为协变了,也就是说实际的定义是FunctionX(-刀):+肉。这么做的原因是:假设我返回了一个肉。那么这个肉一定是食品。我总能用返回类型的父类型取代返回的对象。

这样的行为也是多态一方面的体现——在执行时改变了引用的实际类型。我觉得。这是编译层面上的协变。

三、C#中的样例

ICompareable<in T>强调“可比較”这一功能,是逆变。

IEnumerable<out T>强调的是“可数的”类型。是协变。拿List<T>说明,List<肉>表示“我放了肉在列表里面”,也能够说"我放了食物在列表里面",即能够使用List<食品>取代。

可是不能说“我放了牛肉在列表里面”,所以用List<牛肉>取代是不正确的。

OOP中的逆变和协变的更多相关文章

  1. Java中的逆变与协变

    看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...

  2. Java中的逆变与协变(转)

    看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...

  3. Java中的逆变与协变 专题

    结论先行: PECS总结: 要从泛型类取数据时,用extends: 协变 要往泛型类写数据时,用super: 逆变 既要取又要写,就不用通配符(即extends与super都不用) 不变 List&l ...

  4. C#中的逆变和协变

    msdn 解释如下: “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型. “逆变”则是指能够使用派生程度更小的类型. 解释的很正确,大致就是这样,不过不够直白. 直白的理解: “协变” ...

  5. Java中的逆变与协变 很直接不饶弯的讲出来了

    ```java 协变 extends只能new 辈分比自己低的家伙 List<? extends Number> list001 = new ArrayList<Integer> ...

  6. Java 逆变与协变的名词说明

    最近在研究Thinking in Java的时候,感觉逆变与协变有点绕,特意整理一下,方便后人.我参考于Java中的逆变与协变,但是该作者整理的稍微有点过于概念化,我在这里简单的说一下 我对于协变于逆 ...

  7. Java 逆变与协变

    最近一直忙于学习模电.数电,搞得头晕脑胀,难得今天晚上挤出一些时间来分析一下Java中的逆变.协变.Java早于C#引入逆变.协变,两者在与C#稍有不同,Java中的逆变.协变引入早于C#,故在形式没 ...

  8. .NET Core CSharp初级篇 1-8泛型、逆变与协变

    .NET Core CSharp初级篇 1-8 本节内容为泛型 为什么需要泛型 泛型是一个非常有趣的东西,他的出现对于减少代码复用率有了很大的帮助.比如说遇到两个模块的功能非常相似,只是一个是处理in ...

  9. Scala 深入浅出实战经典 第81讲:Scala中List的构造是的类型约束逆变、协变、下界详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-97讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

随机推荐

  1. 雷锋沙龙 ppt 演讲内容分享(xss,流量劫持的利用)

    http://www.pkav.net/XSS.png?from=timeline&isappinstalled=0

  2. Jscript 随记

    1.Jscript 不能用来编写独立执行的应用程序,而且没有对读写文件的内置支持. 2.注意,语句块中的原始语句以分号结束.但语句块本身并不以分号结束. 3.注意,Jscript 与 C++ 以及其它 ...

  3. Django的Form、CSRF、cookie和session

    Django是一个大而全的web框架,为我们提供了很多实用的功能,本文主要介绍Form.CSRF.cookie和session 一.Form 在web页面中form表单是重要的组成部分,为了数据安全和 ...

  4. STL学习笔记(非变动性算法)

    辅助函数 本节跟以后几节将对所有STL算法逐一详细讨论.为了简化这些例子,我们使用了一些辅助函数,分别用于对容器进行输出跟插入操作. #ifndef ALGOSTUFF_HPP #define ALG ...

  5. scrollTop clientTop offsetTop scrollHeight clientHeight clientWidth的差别及使用方法

    这几个属性做滚动时会经经常使用到.现总例如以下: 首先定义一个div.样式例如以下: <style> *{ margin:0px; padding:0px;} body{ margin:0 ...

  6. win7不休眠方式设置

    方式1:命令行下以管理员方式执行:powercfg -h off 方式2:右键个性化-->屏幕保护程序-->更改电源设置--->更改计算机睡眠时间--->是计算机进入睡眠状态选 ...

  7. xcode 项目证书跟签名都正确的时候,还报证书错误

    原因,安装证书错误,导致无法匹配证书, 方案:删除原来的证书,重新安装 打开终端 1.cd Library/ 2.cd MobileDevice/ 3.open Provisioning\ Profi ...

  8. 《STL源代码剖析》学习笔记系列之七、八——仿函数和配接器

    1. 仿函数 仿函数又名函数对象.具有函数性质的对象.就是传入一些參数.然后对參数进行某些运算,然后返回一个值. 为了可以使行为类似函数,须要在类别定义中必须自己定义function call 运算子 ...

  9. NFS详细分析

    1. NFS服务介绍 1.1什么是NFS服务 NFS(Network File System)即网络文件系统,它允许网络中的计算机之间通过TCP/IP网络共享资源.在NFS的应用中,本地NFS的客户端 ...

  10. bzoj3531【SDOI2014】旅行

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 850  Solved: 433 [Submit][Status ...