先来看一段代码
什么是泛型
public static List list = new ArrayList();
public static void main(String[] args) {
list.add(1);
list.add("2");
System.out.println((Integer)list.get(0));
System.out.println((Integer)list.get(1));
}
这段代码很简单,往列表中添加元素,并在取出的时候将其转换为Integer类型
运行结果不言而喻,在转换第二个元素的时候会出现类型转换异常。这种情况只会在运行的时候将会出现错误,阻塞功能的正常运行。
如何解决这种问题?
最好的解决方案就是在编译期间就检测出来,把一切问题扼杀在源头。于是乎,sun 推出了“泛型”这个概念(当然,这只是泛型的好处之一)
泛型:泛类型,参数化类型;泛化的类型,如考场如战场,反正是那么个意思。
一段代码
可以看到,编译器明显给出了提示,list2可以添加的是String类型,添加int类型不允许。回到A调用B方法的场景,A已经很清楚list2里面存储的是String,想必A也不会再次强制类型转换了对吧?!!
泛型如何表示
可以用任何一切字母代替,如:
T type 类型
E element 元素
K,V 键值对
? 不确定的类型
泛型的使用
1.泛型方法
看代码
public static <V, T> T mapToBean(Map<String, V> map, Class<T> clazz) {
T t = null;
try {
t = clazz.newInstance();
// 一大段反射逻辑
} catch (Exception e) {
}
return t;
}
TestBr testBr = mapToBean(null, TestBr.class);
先说下方法,输入一个map,和一个预期类型,并返回预期的类型对象(pojo),得力于泛型的帮助,这个方法在编译器可以直接返回泛型的实际类型。
如果没有泛型和泛型方法,该方法的第二个参数只能传入Class,并且方法返回值是Object,想使用Object,不好意思,请自己强制类型转换
2.泛型接口
List,Map,Set 集合类都是泛型接口
泛型的边界和通配符
上边界
List<? extends User> list = new ArrayList<>();
特点:不能存储任何元素
下边界
List<? super User> list = new ArrayList<>();
特点可以存储 user 和其子类,但是取出的元素为Object类型
jdk中的使用示例:
Collections类中的这个方法:
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
被比较的对象必须实现Comparator 才能进行比较。通常用在对形参有一些限制的情况下
泛型类型擦除
public class ExceptionForQuiz<T> {
public void test(T t) {
}
}
看下编译后的代码
2.
编译后的:
总结
泛型是在编译期和语法上的一种增强,在运行期间最终的编译结果是没有泛型的信息的,利用其特点我们可以实现 泛型类、泛型方法、边界限定(?extends T,? super T)泛型信息总是会被编译成实际类型,如 会被编译成Object,<? extends Exception> 会被编译成Exception