对协变和逆变的理解(Contravariance and Covariance)
来源:互联网 发布:淘宝手淘搜索怎么增加 编辑:程序博客网 时间:2024/05/17 17:54
本篇博客转载自https://www.zybuluo.com/zhanjindong/note/34147。
数组协变
的语言,好像说了等于没说,别急,慢慢来。我们都知道C#和Java中String类型都是继承自Object的,姑且记做String ≦ Object
,表示String是Object的子类型,String的对象可以赋给Object的对象。
而Object的数组类型Object[],我们可以理解成是由Object构造出来的一种新的类型,可以认为是一种构造类型
,记f(Object)(可以类比下初中数学中函数的定义),那么我们可以这么来描述协变和逆变:
- 当A ≦ B时,如果有f(A) ≦ f(B),那么f叫做
协变
; - 当A ≦ B时,如果有f(B) ≦ f(A),那么f叫做
逆变
; - 如果上面两种关系都不成立则叫做
不可变
。
其实顾名思义,协变和逆变表示的一种类型转变的关系:“构造类型”之间相对“子类型”之间的一种关系。只不过平时我(可能也包括大家)被网上的一些文章搞糊涂了。“协”表示一种自然而然的转换关系,比如上面的String[] ≦ Object[]
,这就是大家学习面向对象编程语言中经常说的:
子类变量能赋给父类变量,父类变量不能赋值给子类变量。
而“逆”则不那么直观,平时用的也很少,后面讲Java泛型中的协变和逆变
会看到例子。
不可变
的例子就很多了,比如Java中List< Object >
和List< String >
之间就是不可变的。
List<String> list1 = new ArrayList<String>();
List<Object> list2 = list1;
这两行代码在Java中肯定是编译不过的,反过来更不可能,C#中也是一样。
那么协变
和逆变
作用到底是什么呢?我个人肤浅的理解:主要是语言设计的一种考量,目的是为了增加语言的灵活性和能力。
里氏替换原则
再说下面内容之前,提下这个大家都知道的原则:
有使用父类型对象的地方都可以换成子类型对象。
假设有类Fruit和Apple,Apple ≦ Fruit,Fruit类有一个方法fun1,返回一个Object对象:
public Object fun1() {
return null;
}
Fruit f = new Fruit();
//...
//某地方用到了f对象
Object obj = f.fun1();
那么现在Aplle对象覆盖fun1,假设可以返回一个String对象:
Override
public String fun1() {return "";
}
Fruit f = new Apple();
//...
//某地方用到了f对象
Object obj = f.fun1();
那么任何使用Fruit对象的地方都能替换成Apple对象吗?显然是可以的。
举得例子是返回值,如果是方法参数呢?调用父类方法fun2(String)的地方肯定可以被一个能够接受更宽类型的方法替代:fun2(Object)......
返回值协变和参数逆变
上面提到的Java和C#语言都没有把函数作为一等公民,那么那些支持一等函数的语言,即把函数也看做一种类型是如何支持协变和逆变的以及里氏原则的呢?
也就是什么时候用一个函数g能够替代其他使用函数f的地方。答案是:
函数f可以安全替换函数g,如果与函数g相比,函数f接受更一般的参数类型,返回更特化的结果类型。《维基百科》
这就是是所谓的对输入类型是逆变的而对输出类型是协变的
Luca Cardelli提出的规则
虽然Java是面向对象的语言,但某种程度上它仍然遵守这个规则,见上一节的例子,这叫做返回值协变
,Java子类覆盖父类方法的时候能够返回一个“更窄”的子类型,所以说Java是一门可以支持返回值协变的语言。
类似参数逆变
是指子类覆盖父类方法时接受一个“更宽”的父类型。在Java和C#中这都被当作了方法重载
。
可能到这又绕糊涂了,返回值协变
和参数逆变
又是什么东东?回头看看协变和逆变的理解。把方法当成一等公民:
构造类型:Apple ≦ Fruit
返回值:String ≦ Object
参数:Object ≧ String
以上都是我个人对协变和逆变这两个概念的理解(欢迎拍砖)。说个题外话:“概念”是个很抽象的东西,之前听到一个不错说法,说概念这个单词英文叫做concept
,con
表示“共同的”,cept
表示“大脑”。
- 对协变和逆变的理解(Contravariance and Covariance)
- 协变(Covariance)与逆变(Contravariance)
- Covariance and Contravariance in Generics(泛型中的协变和逆变)
- .Net 2.0 新功能:委托中的协变与逆变(Covariance and Contravariance in Delegates)
- Delegate(委托)中的Covariance(协变)和Contravariance(逆变)
- 协变(covariance),逆变(contravariance)与不变(invariance)
- 再谈对协变和逆变的理解
- Covariance and Contravariance
- Covariance, Contravariance and Invariance
- Invariance, covariance and contravariance
- Covariance and Contravariance in Java
- c# 逆变 协变的理解
- 型变的理解,逆变与协变
- C# 入门(13) 泛型(generic)、协变(convariance)、逆变(contravariance)
- C#的协变和逆变
- 协变和逆变
- 协变和逆变
- 协变和逆变
- Atitit vod click event design flow 视频点播系统点击事件文档
- opencv 分水岭算法
- atitit.vod search doc.doc 点播系统搜索功能设计文档
- Atitit 全屏模式的cs桌面客户端软件gui h5解决方案 Kiosk模式
- mac linux rename命令行批量修改文件名
- 对协变和逆变的理解(Contravariance and Covariance)
- c++学习笔记--拷贝构造函数
- Atitit vod ver 12 new feature v12 pb2 影吧 视频 电影 点播 播放系统v12新特性
- HDU 2457 DNA repair AC自动机+DP
- Medium 445题 Add Two Numbers II
- 浅析NSTimer & CADisplayLink内存泄露
- 免安装版MySQL(绿色版)配置过程及安装过程中可能出现的问题详解
- HTTP 状态返回码
- masterJ2EE篇003——Tomcat 7.0配置文件部署项目