泛型、协变、反协变

协变 逆变

协变:covariance
逆变:contravariance
我们假设有class A , class B,其中A为B的超类,f表示变换关系。
f是协变的,当且仅当f(A)是f(B)的超类
f是逆变的,当且仅当f(A)是f(B)的子类
f是不变的,当且仅f(A)和f(B)无任何继承关系

泛型

代码编译完成后,编译器会丢弃类型参数的类型信息;因此,此类型信息在运行时不可用。

泛型的子类型变换

List<Parent> p = new ArrayList<>();
List<Child> c = new ArrayList<>();

虽然Parent类是Child类的父类,但List p和List c并没有继承关系。
在这里插入图片描述

由于Set和Set没有任何的继承关系,因此用Set类引用setC是错误的,由于泛型是static checking,因此会在编译阶段报错。

数组的子类型化

在这里插入图片描述如图,Integer是Number的子类,因而Integer[ ]就是Number[ ]的子类。对于Java而言,数组是协变的。

代码擦除:type erasure

类型擦除就是在运行期间,泛型的结构中填写的类型将全部被替换为其上限类型,即extends后的内容(个人理解,就是规定好的能够兼容这个类的“最高父类”),若没有指定上限类型,则将全部被替换为Object。即在编译期间,Set和Set类型是不同的,而在运行期间,类型是相同的。如下图所示。
在这里插入图片描述

通配符

通配符?
1、Set<? extends A> setE
setE的泛型就是A的任何一个子类

2、Set<? super B> setS
setS的泛型就是B的任何一个超类

当类更多用来被读取时,用extends
当类更多用来被写入时,用super

这是因为,对于Set<? extends A> setE ,从SetE中读取的任何元素都可以被A类接受,但是,无法确定写入的是具体的哪个类(及其它的子类)。
此外,Set<? extends Parent> 是 Set的父类
Set<? extends Parent> 是 Set<? extends Child>的父类

总结一下extends A 的用法,? extends A表示所存储类型都是A及其子类,但是获取元素所使用的引用类型只能是T或者其父类。使用上限通配符实现向上转型,但是会失去存储对象的能力。上限通配符为集合的协变表示

对于Set<? Super A> setS ,向SetS中写入的任何元素都可以是A的子类,因为setS中存的元素只能是A与它的超类。但是,一旦要从setS中读出元素,无法确定读出的元素类型,只能知道一定可以用Object类去接受它们,一旦用Object去接受这些类,具体的类就会变得没有意义。因而不适合去读出数据。
此外,Set<? super Parent> 是 Set<? super Child>的子类

下限通配符 ? super T表示 所存储类型为T及其父类,但是添加的元素类型只能为T及其子类,而获取元素所使用的类型只能是Object,因为Object为所有类的基类。下限通配符为集合的逆变表示。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值