JAVA中的协变和逆变

协变逆变的概念

可变性是以一种类型安全的方式,将一个对象当做另一个对象来使用。如果不能将一个类型替换成为另一个类型,那么这个类型就称之为:不变量。

协变:如果某个返回的类型可以由其派生类替换,那么这个类型就是支持协变的。
逆变:如果某个参数类型可以由其基类替换,那么这个类就是支持逆变的。

如Function, 在这里R 作为函数的返回值, 所以这个泛型要协变, 而T用在函数的参数上所以要用逆变

Function<? super Dog,? extends Animal> f1;

协变

如:
List 和List 之间是没有继承关系的.
但是直观上会觉得, Integer 是Number 的子类, 所以List 应是List 的子类.
如果想要这种效果, 就要用协变.
List<? extends Number> 这样 List 就能成为List<? extends Number> 子类, 也就是可以赋值

List<Integer>b = new ArrayList<>();
List<? extends Number> a = b;

逆变

假设有以下继承关系:
车 > 轿车 > 标准轿车 > 高级轿车
现在有一个人声称自己能修理所有的标准轿车, 所以发出了以下公告:

修理(List<标准轿车> cars)

假设我现在有List<轿车>和 List<高级轿车>
那么这个人到底能修理哪个呢? 从上面的函数声明来看都不可以.
再来看看这个人的声明
他说能够修理所有标准轿车
那么因为标准轿车扩展了轿车, 所以如果能够修理标准轿车, 那么应当可以修理轿车
所以这个函数应当可以接受所有标准轿车的父类
也就是说 List<轿车> 能够传入 以List<标准轿车>为参数的函数
换句话说 List<轿车> 是List<标准轿车>的子类, 这样才能传入参数
所以上面的公告要用逆变, 改成如下:

修理(List<? super 标准轿车> cars)

设计模式

里氏替换原则:的内容可以描述为: “派生类(子类)对象可以在程式中代替其基类(超类)对象。”

墨子的智慧

《墨子:小取》中说,“白马,马也;乘白马,乘马也。骊马,马也;乘骊马,乘马也”。文中的骊马是黑的马。意思就是白马和黑马都是马,乘白马或者乘黑马就是乘马。在面向对象中我们可以这样理解,马是一个父类,白马和黑马都是马的子类,我们说乘马是没有问题的,那么我们把父类换成具体的子类,也就是乘白马和乘黑马也是没有问题的,这就是我们上边说的里氏替换原则。

墨子同时还指出了反过来是不能成立的。《墨子:小取》中说:“娣,美人也,爱娣,非爱美人也”。娣是指妹妹,也就是说我的妹妹是没人,我爱我的妹妹(出于兄妹感情),但是不等于我爱美人。在面向对象里就是,美人是一个父类,妹妹是美人的一个子类。哥哥作为一个类有“喜爱()”方法,可以接受妹妹作为参量。那么这个“喜爱()”不能接受美人类的实例,这也就说明了反过来是不能成立的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值