您现在的位置是:亿华云 > IT科技类资讯
5分钟Java短文:泛型之逆变和协变
亿华云2025-10-02 16:11:14【IT科技类资讯】4人已围观
简介本文转载自微信公众号「咸鱼正翻身」,作者MDove 。转载本文请联系咸鱼正翻身公众号。前言日常琐碎的时间下,不适合看一些长篇高质量的文章,但是琐碎时间也是时间,看一些短小精悍的文章来查缺补漏也是极好的
本文转载自微信公众号「咸鱼正翻身」,分钟泛型作者MDove 。短文转载本文请联系咸鱼正翻身公众号。变和
前言
日常琐碎的协变时间下,不适合看一些长篇高质量的分钟泛型文章,但是短文琐碎时间也是时间,看一些短小精悍的变和文章来查缺补漏也是极好的。碎花化的协变时间,就交给“碎片化的分钟泛型文章”来填充吧。
今天“碎片化文章”主题:泛型-逆变和协变。短文逆变和协变摆在这我猜很多朋友会蒙蔽,变和毕竟我们日常好像、协变大概没怎么接触过这个概念。分钟泛型
事实并非如此,短文我们日常开发中经常见,变和只是不知道这么个名词而已。
正文
OK,今天5分钟短文就让咱们聊一聊逆变和协变这俩个概念。
1、基础概念
其实它们俩的概念很好理解。接下来让我们仔细读一遍下边的这一段话:
逆变与协变用来描述类型转换后的继承关系。服务器托管如果A、B表示类型,f(...)表示类型转换,≤表示继承关系(比如,A≤B表示A是B的子类)
如果f(...)是逆变的,那么当A≤B时则f(B)≤f(A)成立
如果f(...)是协变的,那么当A≤B时则f(A)≤f(B)成立
额外补充一条:如果f(...)是不变的,那么当A≤B时则f(B)与f(A)没有任何关系
2、代码场景
如果大家充分理解了上边的话,其实就能想到咱们日常代码中的例子:数组就是一种协变;泛型是不变的。上代码:
public class A extends B { } public class B { } public void test() { B[] arrs = new A[66]; List<B> list = new ArrayList<A>(); }这段代码是编不过的:
因为数组是协变的,所以 A[]是 B[]的子类;而泛型不是,所以 List并不是香港云服务器 List的子类。
3、通配符的意义
因为这个原因的存在,所以才有了通配符。
3.1、协变-上限通配符
代码改成这个样子就可以正常编译了:
通配符的存在,让泛型产生了协变,让 List可以变成 List的子类。不过我猜经验丰富的同学已经知道,这样搞“没什么卵用”,因为:
我们发现,这样搞完。对于 list变量来说,我们只能 get()不能 add()!一时接受不了?其实这里也很好理解,协变之后对于list来说,我可以指向很多 List的子类。
假设此时我们可以随意 add(),那么对于运行期来说简直是灾难:因为我可以随意的 add(newA());add(newC())。如果这种情况存在那么我 get()的时候,是不是只能把它当做 B来使用,因为这里有可能有 A也有可能有 C...
这样搞完全没有意义...因此也就有了下边的服务器租用内容:逆变-下限通配符
3.2、逆变-下限通配符
直接上代码:
public class A extends B { } public class B { } public class C extends B { } public class D extends A { } public void test2(List<? super A> list){ list.add(new A()); list.add(new B()); list.add(new C()); list.add(new D()); }此时我们会发现:我们可以 add(), A及其子类。而这种实现就脱胎于咱们逆变这个概念。
3.3、小思考
如果我们仔细想一想会发现,这些都是在开发阶段或者编译阶段的限制。做了这么多限制,到底为了什么?或者收益是什么样的呢?
关于这部分内容的讨论,咱们后续再聊~
尾声
到此想聊的内容就结束了,关于泛型的话题还有很多很多,而熟练的使用和理解泛型对咱们编写工具、框架有着关键的帮助。
很赞哦!(79667)