总结笔记(一) - Java 泛型总结

泛型总结

泛型是什么?

一句话说就是类型参数化。什么意思呢?参数化的意思就是咱们在定义的时候不知道具体的值,咱们在到咱们实际运行的时候才知道具体的值。类型参数化就是具体类型在定义的时候不知道,在实际运行的时候是肯定的某一个类型。url

Java 是如何实现泛型的?

泛型是不少高级语言都有的特性。根据定义,泛型在运行时表示同一个类型,咱们比较容易想到 List<A>List<B> 用 2 个不一样的 Class 表示,这个是可行的,可是 Java 因为须要兼容支持旧的代码,并且在推出泛型前就提供了容器类,这种方式(List<A>List<B> 用 2 个不一样的 Class)没法兼容之前的老代码,因此这个实现方法不适用。因此 Java 大佬们想了另一种方式来实现泛型,这种方式就是类型擦除.net

什么是泛型的类型擦除呢?

类型擦除就是在实际生成字节码的时候,编译器源码里面定义的 List<A> 变成了 List<Object>,源码里面定义的 A Class擦除了,变成了 Object,同时在使用的时候,会强制类型转换,把取出来的 object 转成 A 的实例去使用。这就是类型擦除。code

初步看,泛型擦除好像是没什么大的问题,可是仔细想一想,在强制类型转换的时候,因为会丢掉类型的一些信息,会致使一些不符合预期的事情。好比有个基类 A,和它的两个子类 B 和 C ,而后咱们有下面的一段代码。get

List<A> listA = new ArrayList<A>();
listA.add(new B()); // 错误的,

第二行代码是不符合预期的,由于 listA 里面指望放的是 A 而不是 B。 可是这个好像不太符合预期,咱们有时候但愿子类是能够放进容器里面的。可是若是支持这个操做的话,会发生什么呢?取出来来的是 B 仍是 C ?若是不能明确,那么就没有实现“泛型”。编译器

为了解决这个问题, Java 大佬们想了个方法,提出了一些通配符来解决这些问题。源码

泛型的通配符 ?extendssuper

在理解通配符以前,咱们须要知道的是,通配符的发明是为了解决什么问题?至少要解决的一个问题是:容器里面放进去的是什么,取出来的就是什么。io

这个问题,其实分两步,放进去,是说放进去同一种类型的东西。取出来,是说取出同一种类型的东西。或者说,用到通配符的地方应该是在不一样的地方,一个地方把数据写到容器,另一个地方把数据从容器拿出来,若是实在同一个代码块里写入和读取数据到同一个容器,应该是知道具体类型的,是不须要用到通配符的。编译

? 通配符

? 通配符称为无限通配符,表示不肯定或者不关心类型。class

extends 通配符

通常称为上界通配符,表示的意思是:取值范围为 (某个类的子类, 某个类]。再想一想咱们以前说的,通配符要解决的问题?放进去的是什么,取出来的就应该是什么。放数据和取数据应用在不一样的场景。若是咱们在同一个场景,就不须要用到通配符了,由于类型是已知的。容器

经过上面的表述,容易推断出来 <? extends E> 的集合只能往外拿数据,由于取出来的必定是 E ,可是放进去的不知道是什么,多是 E ,也多是 E 的子类,若是容许往集合里面放东西,就不能保证放进去的是什么,拿出来的就是什么了。由于只能保证拿出来的是 E

这个特性也叫作协变。

super 通配符

通常称为下界通配符,表示的意思是:取值范围为 [某个类,这个类的父类)。结合上面小节的解释,能够推断出 <? super S> 的集合只能往里面放数据,而不能从里面拿东西,为何呢?由于 <? extends E> 解决的就是拿出来的问题啊,因此这个解决的就是放进去的问题啊,囧。里面放的是下限或者下限的子类。

这个特性也叫作逆变。

小结

通配符与一个规则, PE-CS

  • PE 简单的说,当只想从集合中获取元素,请把这个集合当作生产者,请使用<? extends T>,这就是 Producer extends 原则,PECS原则中的PE部分。集合生产元素后,就能够拿过来用了。

  • CS 简单的说,当你仅仅想增长元素到集合,把这个集合当作消费者,请使用<? super T>。这就是 Consumer super 原则,PECS原则中的CS部分。集合消费元素,这样就能够往里面放了

  • 同时做为生产者和消费者的状况不存在,由于你能够指定具体的泛型。

参考资料:

相关文章
相关标签/搜索