OOP中的逆变和协变
逆变和协变在存在于强类型语言中,尽管非常少提及。可是里面蕴含了面向对象的世界观。感谢和我一起讨论这个问题的人。
这里用了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中的逆变和协变的更多相关文章
- Java中的逆变与协变
看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...
- Java中的逆变与协变(转)
看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...
- Java中的逆变与协变 专题
结论先行: PECS总结: 要从泛型类取数据时,用extends: 协变 要往泛型类写数据时,用super: 逆变 既要取又要写,就不用通配符(即extends与super都不用) 不变 List&l ...
- C#中的逆变和协变
msdn 解释如下: “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型. “逆变”则是指能够使用派生程度更小的类型. 解释的很正确,大致就是这样,不过不够直白. 直白的理解: “协变” ...
- Java中的逆变与协变 很直接不饶弯的讲出来了
```java 协变 extends只能new 辈分比自己低的家伙 List<? extends Number> list001 = new ArrayList<Integer> ...
- Java 逆变与协变的名词说明
最近在研究Thinking in Java的时候,感觉逆变与协变有点绕,特意整理一下,方便后人.我参考于Java中的逆变与协变,但是该作者整理的稍微有点过于概念化,我在这里简单的说一下 我对于协变于逆 ...
- Java 逆变与协变
最近一直忙于学习模电.数电,搞得头晕脑胀,难得今天晚上挤出一些时间来分析一下Java中的逆变.协变.Java早于C#引入逆变.协变,两者在与C#稍有不同,Java中的逆变.协变引入早于C#,故在形式没 ...
- .NET Core CSharp初级篇 1-8泛型、逆变与协变
.NET Core CSharp初级篇 1-8 本节内容为泛型 为什么需要泛型 泛型是一个非常有趣的东西,他的出现对于减少代码复用率有了很大的帮助.比如说遇到两个模块的功能非常相似,只是一个是处理in ...
- Scala 深入浅出实战经典 第81讲:Scala中List的构造是的类型约束逆变、协变、下界详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-97讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
随机推荐
- POJ 1040 Transportation
链接:http://poj.org/problem?id=1040 Transportation Time Limit: 1000MS Memory Limit: 10000K Total Submi ...
- 关于angularjs dom渲染结束再执行的问题
情景 当我点击了button, div才能显示.并且我想知道这个div的高度. 问题 当我点击这个button以后这个.chrome就然告诉我这个div高度是0.这不是睁着眼睛说瞎话吗?怎么能如此欺骗 ...
- WordPress安全检测工具
Wordpres是一款非常流行cms系统,市面上有相当一部分的博客和站点都是使用wordpress搭建.正因为大多博客都使用wordpress,所以其安全性就显得尤为重要. 我们平时维护一个站点(不仅 ...
- SQL JOB 调用 SSIS package 权限问题
来自: http://www.cnblogs.com/sodacc/archive/2012/11/26/2789135.html 第一次用SQL给SSIS包排JOB的时候,都会遇到这样一个问题:单独 ...
- WCF configure
1. maxBufferSize 一个正整数,指定内存中用于存储消息的缓冲区的最大大小(字节). 如果 transferMode 属性等于 Buffered,则此属性应等于 maxReceivedMe ...
- DialogFragment创建默认dialog
代码地址如下:http://www.demodashi.com/demo/12228.html 记得把这几点描述好咯:代码实现过程 + 项目文件结构截图 + 演示效果 前言 在我们项目的进行中不可避免 ...
- centos安装pip Xvfb Selenium
pip安装命令: python -V wget https://bootstrap.pypa.io/get-pip.py python get-pip.py Xvfb安装命令: yum install ...
- mysql用merge合并表
merge合并表的要求 1.合并的表使用的必须是MyISAM引擎 2.表的结构必须一致,包括索引.字段类型.引擎和字符集 实例: create table if not exists user1( i ...
- 浅析VS2010反汇编 VS 反汇编方法及常用汇编指令介绍 VS2015使用技巧 调试-反汇编 查看C语言代码对应的汇编代码
浅析VS2010反汇编 2015年07月25日 21:53:11 阅读数:4374 第一篇 1. 如何进行反汇编 在调试的环境下,我们可以很方便地通过反汇编窗口查看程序生成的反汇编信息.如下图所示. ...
- .Net 异步调用
.NET异步编程之新利器——Task与Await.Async 一. FrameWork 4.0之前的线程世界 在.NET FrameWork 4.0之前,如果我们使用线程.一般有以下几种方 ...