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<牛肉>取代是不正确的。

时间: 2024-12-14 07:34:55

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

Java中的逆变与协变(转)

看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); //type mismatch List<? extends Number> list = new ArrayList<Number>(); list.add(new Integer(1)); //error list.add(new Float(1.2f)); //error 有人会

Java中的逆变与协变

看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); //type mismatch List<? extends Number> list = new ArrayList<Number>(); list.add(new Integer(1)); //error list.add(new Float(1.2f)); //error 有人会

Java中的逆变和协变

// public final class Integer extends Number Number num = new Integer(1); List<Number> list = new ArrayList<>(); list.add(new Integer(3)); ArrayList<Number> list = new ArrayList<Integer>(); //type mismatch List<? extends Number&

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

http://blog.csdn.net/z69183787/article/details/51598345 看下面一段代码: Number num = new Integer(1); List<Number> list = new ArrayList<>(); list.add(new Integer(3)); ArrayList<Number> list = new ArrayList<Integer>(); //type mismatch List&

Java 逆变与协变

最近一直忙于学习模电.数电,搞得头晕脑胀,难得今天晚上挤出一些时间来分析一下Java中的逆变.协变.Java早于C#引入逆变.协变,两者在与C#稍有不同,Java中的逆变.协变引入早于C#,故在形式没有C#直观(Google推出的基于jvm的Kotlin语音,则完全走向了C#的路线).Java中逆变.协变,在泛型集合使用中更多些.更直观(像C#中的用法在Java中较少出现,但并非不可). 正常泛型集合的使用 示例代码如下: public static void main(String[] arg

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

王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-97讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 腾讯微云:http://url.cn/TnGbdC 360云盘:http://yunpan.cn/cQ4c2UALDjSKy 访问密码 45e2土豆:http://www.tudou.com/programs/view/ceac2IoB-ik/优酷:http://v.youku.com/v_show/id_

Scala中List的构造是的类型约束逆变、协变、下界详解

学习了Scala中List的构造是的类型约束逆变.协变.下界详解,列表中用::加入父类的对象,列表会协变为父类,例子如下: Def :: [B>:A](x:B):List(B)= New scala:collection.imutable.::(x,this) 王家林亲授<DT大数据梦工厂>大数据实战视频“Scala深入浅出实战经典”视频.音频和PPT下载!第81讲:Scala中List的构造是的类型约束逆变.协变.下界详解腾讯微云:http://url.cn/UNeLA2百度云盘:ht

C# 逆变与协变

原文:C# 逆变与协变 该文章中使用了较多的 委托delegate和Lambda表达式,如果你并不熟悉这些,请查看我的文章<委托与匿名委托>.<匿名委托与Lambda表达式>以便帮你建立完整的知识体系. 在C#从诞生到发展壮大的过程中,新知识点不断引入.逆变与协变并不是C#独创的,属于后续引入.在Java中同样存在逆变与协变,后续我还会写一篇Java逆变协变的文章,有兴趣的朋友可以关注一下. 逆变与协变,听起来很抽象.高深,其实很简单.看下面的代码: class Person {

逆变和协变的意义

逆变和协变在存在于强类型语言中,虽然很少提及,但是里面蕴含了对问题的描述.感谢和我一起讨论的人. 这里,使用C#.Scala中都包含逆变的参数声明方式. 一.逆变的定义 逆变的参数可以由指定的类型的子类型代替,Scala中的逆变声明:Function1[-A,+B] ;参数可以使用A类型或者A类的子类型. 二.协变与逆变的用途不同 1.语义 常见的地方用在Function的传入参数中,Function1[-A,+B] 输入的逆变表示"只要满足这种功能即可",所以满足的功能,在A的子类中