其实关于这块知识大概两年以前就有了个比较全的了解了吧,重新整理一下用自己的话写出来又是一次加深理解的过程。下面我大概会分三个方面去讲泛型,1、泛型的主要相关特性 2、怎么用泛型 3、泛型总结
1、泛型的主要相关特性
背景介绍:
Java泛型(generics)是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter)。声明的类型参数在使用时用具体的类型来替换。泛型最主要的应用是在JDK 5中的新集合类框架中。对于泛型概念的引入,开发社区的观点是褒贬不一。从好的方面来说,泛型的引入可以解决之前的集合类框架在使用过程中通常会出现的运行时刻类型错误,因为编译器可以在编译时刻就发现很多明显的错误。而从不好的地方来说,为了保证与旧有版本的兼容性,Java泛型的实现上存在着一些不够优雅的地方。当然这也是任何有历史的编程语言所需要承担的历史包袱。后续的版本更新会为早期的设计缺陷所累。
a、类型擦除
正确理解泛型概念的首要前提是理解类型擦除(type erasure)。 Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节代码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。这个过程就称为类型擦除。还是上例子吧,如下:
泛型擦除导致编译不通过按照我们对于重载的理解,方法参数类型不一样应该是可以定义的啊,这个理论一直是成立的。主要原因是在于泛型是在编译的时候类型会擦除,这样两个方法的参数类型都是List,是不带参数的噢。所以重载不通过导致编译不通过。
b、泛型在初始化、实例化的时候需要知道确切的类型
泛型在没有申明具体的类型的时候是不能进行实例化,因为它在此时只是一个代号,换句话说我创建一个对象的过程要经历,加载、连接、初始化、实例化。我连你的基本信息都不知道我怎么进行下去啊,上例子,如下:
泛型不知道具体类型初始化编译不通过这种情况下new T()编译失败。
c、泛型和子类型
我们知道在java中存在 父类 a = new 子类(); 这种写法是成立的而且是一个比较好的写法。但是List<父类> list = new ArrayList<子类>(); 这种写法会成立吗,事实是没有成立编译会报错,上例子:
泛型和子类型转换关系为什么会这样呢,应该这么理解如果这种写法成立的话,那我fruits就可以add Child2、Child3等其他子类了。
到时候我从fruits里面取出来集合里面的元素的时候我应该转换成Child、Child2、Child3 ??? 编译器也不知道啊。
d、泛型通配符
我想在通配符这个点我会多讲一点。
d1、通配符?
这里使用了通配符?指定可以使用任何类型的集合作为参数。读取的元素使用了Object类型来表示,这是安全的,因为所有的类都是Object的子类。这里就又出现了另外一个问题,如下代码所示,如果试图往使用通配符?的集合中加入对象,就会在编译时出现错误。需要注意的是,这里不管加入什么类型的对象都会出错。这是因为通配符?表示该集合存储的元素类型未知,可以是任何类型。往集合中加入元素需要是一个未知元素类型的子类型,正因为该集合存储的元素类型未知,所以我们没法向该集合中添加任何元素。唯一的例外是null,因为null是所有类型的子类型,所以尽管元素类型不知道,但是null一定是它的子类型。另一方面,我们可以从List lists中获取对象,虽然不知道List中存储的是什么类型,但是可以肯定的是存储的类型一定是Object的子类型,所以可以用Object类型来获取值。如for(Object obj: lists),这是合法的。
还是上代码:
通配符?样例代码
d2、?extends通配符
其实这个也好理解,可以理解为某个接口或者某个抽象类的所有实现类,上例子:
List<? extends Serializable> 中存放的是所有的Serializable的实现类,如可能是String、Integer等
我们在取出来的时候就可以转换成Serializable ,但是我们还是不能往里面add元素原因跟上面通配符 ?一样
d3、?super通配符
这里还有一种边界通配符为?super,可以表示当前类或者当前类的父类,还是上例子吧:
?super通配符使用e、泛型的推断
自Java SE 7起, 你可以使用一个空的类型参数集合 (<>)代替构造器的参数化类型:Map<String, List> myMap = new HashMap<>();注意:想要在泛型类初始化期间利用自动类型推断。
2、怎么用泛型
上面主要介绍了一些泛型的主要特性吧,下面我还是想说说怎么使用泛型吧。
泛型用自己的话来说就是“参数化类型”,在各种实体类型的基础上抽象出一个虚拟的类型,你可以叫A、B、C、T等。
具体的使用可以有两种比较常见的表现形式,类泛型 、方法泛型
a、类泛型
从字面上理解为你定义的泛型是整个类通用的或者是类里面所有的泛型类型就引用类上的自己方法上不额外定义,例子如下:
类泛型定义 类泛型实现从上面可以看出类中定义了请求类型为Request返回类型为Response这个为了可读性强一点这么定义,在process抽象方法中直接用Request,Response来表示方法所需要的类型。
在实现类中就可以用具体的String、Integer代替接口中申明的泛型类型。
b、方法泛型
方法泛型我感觉就没类泛型那么抽象性高,可以为每一个方法来独自定义自己的类型了,上例子:
方法泛型实现如上是一个简单的将List 里面的实体用某个字段作为key转换到Map中,中间的转换过程TODO.
方法上应用了K,V两个类型,但是这两个类型是需要申明定义的,所以在方法修饰符后面要自定义一下类型,如果不定义<K,V>是要编译出错的。
3、泛型总结
上面1、2部分介绍了泛型的一些主要特性和常用用法以后,我们对于泛型的认识应该是比较清晰的,所有的哪怕是泛型的复杂应用都是从上面讲的一些演变过来了,其实挺简单的。什么时候用泛型这个需要自己去思考?总之我觉得能够抽象出一个统一的类型就可以用。。。
3 Q very much!!!
网友评论