文档章节

泛型协变、逆变

obaniu
 obaniu
发布于 08/20 16:47
字数 592
阅读 36
收藏 0

无论是java、C#、kotlin还是scala,都会遇到泛型中的协变、逆变场景,算是泛型必学技。本文的概念、思想在其他三门语言也是通用的,学会包您一招通杀。

概念

假设

  • A、B表示类型
  • ≤ 表示继承关系
  • f<⋅>表示类型转换

若A ≤ B,则 A是B的子类,B是A的超类

协变、逆变

什么是型变?型变(type variance)允许对类型进行子类型转换。

为了下面讲解先定义几个类:

static class Animal {}
static class Human extends Animal {}
static class Wolf extends Animal {}
static class Man extends Human {}

1. 协变(covariant)

当A≤ B有 f<A> ≤f <B>

List<? extends Animal> list=new ArrayList<Human>();

子类通配符(也叫上界通配符)<? extends T>

规定了元素的根类是Animal,可get出Animal类型

Animal animal=list.get(0);

但不能add,继承自Animal的类型可以是Human也可以Wolf,若添加Wolf肯定出错所以编译器禁止

list.add(new Human());
list.add(new Wolf());

java中的数组默认支持协变的

Animal []array=new Animal[3];
array[0]=new Human();
array[1]=new Wolf();
array[2]=new Man();

2. 逆变(contravariant)

当A≤B有 f<B>≤f<A>

List<? super Human> list=new ArrayList<Animal>();

超类通配符(也叫下界通配符)<? super T>

规定了元素的超类是Human,所以可以add Human类型及其子类型

list.add(new Human());
list.add(new Man());

不可以 get Human类型,因为没明确指定统一的“根”(除Object),只能get出Object类型

Human h=list.get(0);

3. 不变(invariant)

当A≤B时上述协变、逆变均不成立

List<Object> list=new ArrayList<String>();

Java的泛型默认是不变的(在不使用上界/下界通配符的情况下)

生产者协变,消费者逆变

哪么实际使用中何时协变何时逆变呢?《Effective Java》总结好了:producer-extends, consumer-super(PECS)

  • 读取(get)的对象称为生产者(Producer),可从生产者中安全地读取;
  • 写入(add)的对象称为消费者(Consumer) ,可对消费者写入该类型和字类型(Human和Human的子类Man)。

© 著作权归作者所有

共有 人打赏支持
obaniu
粉丝 35
博文 81
码字总数 38691
作品 0
广州
高级程序员
私信 提问
谈谈.Net中的协变和逆变

谈谈.Net中的协变和逆变 关于协变和逆变要从面向对象继承说起。继承关系是指子类和父类之间的关系;子类从父类继承所以子类的实例也就是父类的实例。比如说Animal是父类,Dog是从Animal继承的...

长平狐
2012/06/08
78
0
c#中关于协变性和逆变性(又叫抗变)详解

  今天回忆了之前看的《深入理解C#》这本书中的泛型章节,其中对泛型的可变性的理解。泛型可变性分两种:协变和逆变。逆变也又称为抗变。  怎么理解这两个名词的意思:   ①:协变即为在...

奥斯卡的肌肤
08/20
0
0
协变和逆变(转载)

前言 个人感觉协变(Covariance)与逆变(Contravariance)是 C# 4 中最难理解的一个特性了,因为 C# 4 用了一个非常直观的语法(和关键字),在很多情况下,这似乎很简单,用于输入的参数,用于...

jeffcky
2015/08/15
0
0
一句话清晰总结协变和逆变

看到过园子里面几篇协变和逆变的文章,但是总觉得写得不够清晰,文章这东西注重要是要把自己想表达的观点表达出来,这个过程应该是把复杂的东西消化出来从而简单化,清晰化,而不是故弄玄虚,...

长平狐
2012/06/08
42
0
C# 4.0新特性-"协变"与"逆变"以及背后的编程思想

在《上篇》中我们揭示了“缺省参数”的本质,现在我们接着来谈谈C#4.0中另一个重要的新特性:协变(Covariance)与逆变(Contravariance)。对于协变与逆变,大家肯定不会感到陌生,但是我相...

长平狐
2012/09/04
38
0

没有更多内容

加载失败,请刷新页面

加载更多

Confluence 6 教程:在 Confluence 中导航

当你对 Confluence 有所了解后,你会发现 Confluence 使用起来非常简单。这个教程主要是针对你使用的 Confluence 界面进行一些说明,同时向你展示在那里可以进行一些通用的任务和操作。 空间...

honeymose
21分钟前
2
0
sed, awk 练习

1. sed打印某行到某行之间的内容 2. sed 转换大小写 将单词首字母转化大写 将所有小写转化大写 3. sed 在某一行最后面添加一个数字 4. 删除某行到最后一行 解析: {:a;N;$!ba;d} :a : 是...

Fc丶
今天
2
0
babel6升级到7,jest-babel报错:Requires Babel "^7.0.0-0", but was loaded with "6.26.3".

自从将前端环境更新到babel7,jest-babel之前是基于babel6的,执行时候就会报:Requires Babel "^7.0.0-0", but was loaded with "6.26.3". 很烦,因为连续帮好几台电脑修复这个问题,所以记...

曾建凯
今天
1
0
探索802.11ax

802.11ax承诺在真实条件下改善峰值性能和最差情况。 如何改善今天的Wi-Fi? 在决定如何改进当前版本以外的Wi-Fi时,802.11ac,IEEE和Wi-Fi联盟调查了Wi-Fi部署和行为,以确定更广泛使用的障碍...

linuxprobe16
今天
2
0
使用linux将64G的SDCARD格式化为FAT32

一、命令如下: sudo fdisk -lsudo mkfs.vfat /dev/sda -Isudo fdisk /dev/sda Welcome to fdisk (util-linux 2.29.2). Changes will remain in memory only, until you decide to wri......

mbzhong
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部