1、什么是泛型?
泛型(Generics )是把范例参数化,运用于类、接口、要领中,可以通过执行泛型范例挪用 分派一个范例,将用分派的详细范例替换泛型范例。然后,所分派的范例将用于限制容器内利用的值,这样就无需举办范例转换,还可以在编译时提供更强的范例查抄。
2、泛型有什么用?
泛型主要有两个长处:
(1)消除显示的强制范例转换,提高代码复用
(2)提供更强的范例查抄,制止运行时的ClassCastException
3、泛型的利用
范例参数(又称范例变量)用作占位符,指示在运行时为类分派范例。按照需要,大概有一个或多个范例参数,而且可以用于整个类。按照老例,范例参数是单个大写字母,该字母用于指示所界说的参数范例。下面列出每个用例的尺度范例参数:
E:元素 K:键 N:数字 T:范例 V:值 S、U、V 等:多参数环境中的第 2、3、4 个范例 ? 暗示不确定的java范例(无限制通配符范例)
4、有界泛型
<? extends T>:是指 “ 上界通配符 (Upper Bounds Wildcards) ”
<? super T>:是指 “ 下界通配符 (Lower Bounds Wildcards) ”
—这里有个坑
举个例子,如下,注释的部门是编译不通过的。
/** * @author Sven Augustus */ public class Test { static class Species{} static class Human extends Species{} static class Man extends Human{} static class Woman extends Human{} public static void main(String[] args) { List<Human> list = new ArrayList<Human>(); list.add(new Man()); list.add(new Woman()); // Man o11 = (Man) list.get(0); // 这不能担保转型乐成,也不是泛型的初志 Human o12 = list.get(0); List<? extends Human> list2 = new ArrayList<Human>(); // list2.add(new Object()); // 编译错误:这不能写入元素,范例校验失败 // list2.add(new Species()); // 编译错误:这不能写入元素,范例校验失败 // list2.add(new Human()); // 编译错误:这不能写入元素,范例校验失败 // list2.add(new Man()); // 编译错误:这不能写入元素,范例校验失败 // list2.add(new Woman()); // 编译错误:这不能写入元素,范例校验失败 // Man o21 = (Man) list2.get(0);// 这不能担保转型乐成,也不是泛型的初志 Human o22 = list2.get(0); List<? super Human> list3 = new ArrayList<Human>(); // list3.add(new Object()); // 编译错误:这不能写入元素,范例校验失败 // list3.add(new Species()); // 编译错误:这不能写入元素,范例校验失败 list3.add(new Human()); list3.add(new Man()); list3.add(new Woman()); // Man o31 = (Man) list3.get(0); // 这不能担保转型乐成,也不是泛型的初志 // Human o32 = list3.get(0); // 编译错误:无法自动转型为 Number Object o33 = list3.get(0); } }
那么我们看到
如 List<? extends T> 各人觉得元素为 T以及其所有子类的工具 的List。其实不是。元素范例 仅指T的某一个不确定的子类,软件开发,软件开发,是单一的一个不确定类,没有详细哪个类。因此不能插入一个不确定的。
List<? super T> 各人觉得元素为 T以及其父类的工具 的List。其实不是,元素范例 仅指T的某一个不确定的父类,是单一的一个不确定类(只确定是T的父类),没有详细哪个类。
因此:
不能往List<? extends T>中插入任何范例的工具。独一可以担保的是,你可以从中读取到T可能T的子类。
可以往List<? super T>中插入T可能T子类的工具,但不行以插入T父类的工具。可以读取到Object可能Object子类的工具(你并不知道详细的子类是什么)。
我们总结一下:
5、范例擦除
Java的泛型在编译期间,所有的泛型信息城市被擦除去。
Class c1 = new ArrayList<Integer>().getClass(); Class c2 = new ArrayList<Long>().getClass(); System.out.println(c1 == c2);
这就是 Java 泛型的范例擦除造成的,因为不管是 ArrayList<Integer> 照旧 ArrayList<Long>,在编译时城市被编译器擦除成了 ArrayList。Java 之所以要制止在建设泛型实例时而建设新的类,从而制止运行时的太过耗损。
6、泛型范例信息
那么,假如我们确实某些场景,如HTTP或RPC或jackson需要获取泛型举办序列化反序列化的时候,软件开发,需要获取泛型范例信息。