协变逆变java_Java中的逆变与协变
什么是逆变与协变
协变(Covariance)
如果B是A的子类,并且F(B)也是F(A)的子类,那么F即为协变
逆变(Contravariance)
如果B是A的子类,并且F(B)成了F(A)的父类,那么F即为逆变
Java中的逆变与协变
Java中的泛型有逆变和协变两种操作,定义如下:
协变
extends A>
B是A的子类,那么List< B >是List extends A>的子类
逆变
supper A>
B是A的子类,那么List< B >是List super A>的父类
Java中逆变与协变的约束
Java的协变逆变及其约束,都是出于对多态的应用。为了后续说明方便,这里先定义一系列的父子类
class Fruit {
public String returnMeat() {
return "generic fruit meat";
}
}
class Apple extends Fruit {
@Override
public String returnMeat() {
return "apple meat";
}
}
class GreenApple extends Apple {
@Override
public String returnMeat() {
return "green apple meat";
}
}
多态
Java是支持多态的。如果一个方法的参数接收的是A类型,那么将其子类型作为参数,调用该方法,依然可行。
例如eatFruitMeat方法就能体现多态特性
@Test
public void test1() {
eatFruitMeat(new Fruit());//输出eat generic fruit meat
eatFruitMeat(new Apple());//输出eat apple meat
eatFruitMeat(new GreenApple());//输出eat green apple meat
}
public void eatFruitMeat(Fruit fruit) {
System.out.println("eat "+fruit.returnMeat());
}
协变约束
协变方法支持对传入参数的读操作,但不支持修改操作。如下:
@Test
public void test1() {
List greenApples = Lists.newArrayList(new GreenApple());
List fruits = Lists.newArrayList(new Fruit());
List apples = Lists.newArrayList(new Apple());
eatFruitMeats(greenApples);
eatFruitMeats(fruits);//编译错误1
eatFruitMeats(apples);
}
public void eatFruitMeats(List extends Apple> fruits) {
fruits.forEach(fruit->System.out.println("eat "+fruit.returnMeat()));
fruits.add(new Apple());//编译错误2
fruits.add(new Fruit());//编译错误3
fruits.add(new Object());//编译错误4
}
编译错误1: eatFruitMeats方法接受的List extends Apple>的子类,显然List不是其子类
编译错误2,3,4: eatFruitMeats方法在被调用前,并不知道最终调用方,传递进来的具体是哪一个子类?有可能是List< Apple >,也有可能是List< GreenApple >,所以贸然向其中添加任何对象,都是可能出错,比如你不能把一个Apple对象放进List< GreenApple >。为了防止这些可能的错误,编译器提前进行了约束限制。
逆变约束
逆变主要在写的场景,即只能向逆变容器中添加,下界类型本身或其子类
@Test
public void test1() {
List fruits = Lists.newArrayList();
List apples = Lists.newArrayList();
List greenAppleLists = Lists.newArrayList();
collectFruits(fruits);
collectFruits(apples);
collectFruits(greenAppleLists);//编译错误1
}
public void collectFruits(List super Apple> fruits) {
fruits.add(new Fruit());//编译错误2
fruits.add(new Apple());
fruits.add(new GreenApple());
}
编译错误1: 由于是逆变,所以List是List super Apple>的父类。所以不能将greenAppleLists作为参数调用collectFruits方法,因为不满足 Java 方法参数的多态性要求,即只能传本类或子类的要求
编译错误2: 如果调用方传递的是List< Apple >,那往其中添加父类Fruit对象,在运行时肯定会报错,为了避免这种情况,编译器提前报错。
总结
Java泛型支持协变和逆变,具体在使用时,会有一些约束。这些约束,需要从Java语言的特性,比如多态性,以及运行时安全性去理解。
简单总结协变、逆变参数的方法调用特点如下:
协变参数
只接受自己的子类。协变的父子关系,同类原本的父子关系一致。如GreenApple是Apple的子类,List< GreenApple >是List extends Apple>的子类
对写有约束,只能用于读
逆变参数
只接受自己的子类。逆变的父子关系,同类原本父子关系相反。如GreenApple是Apple的子类,List< GreenApple >是List super Apple>的父类
只能写入下界的子类,本例中,只能向List中写入Apple及Apple的子类
参考链接
协变逆变java_Java中的逆变与协变相关推荐
- 协变逆变java_Java中的协变与逆变
Java作为面向对象的典型语言,相比于C++而言,对类的继承和派生有着更简洁的设计(比如单根继承). 在继承派生的过程中,是符合Liskov替换原则(LSP)的.LSP总结起来,就一句话: 所有引用基 ...
- 跟着小老弟来学习Kotlin中的逆变和协变
/ 今日科技快讯 / 近日,小米创始人.董事长兼CEO雷军在抖音上开启了其直播带货的首秀.从晚上8点开播,到晚上10点,销售额就已经破亿.包括1000台售价49999元的透明电视在内的商品一推 ...
- java中的逆变、协变、不变概念讲解转载自http://www.cnblogs.com/en-heng/p/5041124.html,感谢编程路上的前辈们!
En-Heng 无他,但手熟尔 博客园 首页 新随笔 联系 订阅 管理 随笔 - 32 文章 - 0 评论 - 33 Java中的逆变与协变 看下面一段代码 Number num = new In ...
- 工频风力发电储能逆变电路中的电流检测(霍尔电流传感器ACS712/CH701应用案例)
在传统的风力发电中,由于风力的不稳定性,因此直接产生的电压不稳定,不能直接被利用,需要进一步的稳压,储能,转化才能实现正常的使用. 为了克服传统的风力发电问题,本文介绍了一种工频风力发电储能逆变电路, ...
- UPS电源中的逆变电路与Simulink仿真
一.设计题目: UPS电源中的逆变电路 主要指标及要求: 输入电压240V 输出电压220/230/240V 效率>90% 二.设计思路.方案选择及电路工作原理: 采用单相全桥逆变电路,并使用双 ...
- 倒序存放数组java_java实现数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对,例如在数组{7,5,6,4}中,一共存在5对逆序对,分别是{7,6},{7,5},{7,4},{6,4},{5,4}.输 ...
- 教你如何攻克Kotlin中泛型型变的难点(下篇)
简述: 前几天我们一起为Kotlin中的泛型型变做了一个很好的铺垫,深入分析下类型和类,子类型和子类之间的关系.什么是子类型化关系以及型变存在的意义.那么今天将会讲点更刺激的东西,也就是Kotlin泛 ...
- 教你如何攻克Kotlin中泛型型变的难点(应用篇)
简述: 这是泛型型变最后一篇文章了,也是泛型介绍的最后一篇文章.顺便再扯点别的,上周去北京参加了JetBrains 2018开发者日,主要是参加Kotlin专场.个人感觉收获还是挺多的,bennyHu ...
- 面试题36:数组中的逆序对
题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数.例如,有一个数组为Array[0..n] 其中有元素a[i],a[j]. ...
最新文章
- Keras入门(一)搭建深度神经网络(DNN)解决多分类问题 1
- c#中的interface abstract 与 virtual(转)
- 计算机英语讲课笔记03
- opencv 伽马变换
- python包标准类型和动态导入模块和多态和反射和授权
- 线性同余算法 (LCG)
- 格雷码与二进制相互转换的verilog实现
- 安科瑞配电室综合监控系统实现配电室内环境的在线监测,保障配电室设备的安全运行
- 回归分析——简单线性回归实例讲解(SPSS)
- Ordering disordered structures
- 电脑复制,电脑复制粘贴,详细教您电脑不能复制粘贴怎么办
- Proxmox监视器
- matlab读多个excel,读取excel 多个表格文件数据-怎样利用matlab去读取一个excel表中多个sheet的数......
- WINVNC(二)omni_thread
- 记录通过的阿里云认证
- 四通畜牧数据库使用说明
- Java if判断,while判断,Do while判断,Switch判断
- 雷达原理习题【西电】
- 1. 无法解析的外部符号 “__declspec(dllimport) const XXX::vftable“ ` 2. `无法定义 dllimport 实体`
- 对话黄骁俭:SAP的工程师文化