【java基础】泛型

来源:互联网 发布:数学建模 知乎 编辑:程序博客网 时间:2024/05/22 01:41

泛型


学习笔记,精简篇幅,用于知识点回顾。详情参考底部链接。

简介

泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

泛型的产生是为了解决以下问题:
List默认的类型为Object类型,可随意插入各种类型的对象,取出时又要强制转换类型,运行时还可能出现 java.lang.ClassCastException 异常。

List<String> list = new ArrayList<String>();list.add("xulinfeng");list.add("csdn");//list.add(100);   // 1  编译即报错for (int i = 0; i < list.size(); i++) {    String name = list.get(i); // 2 不需要类型转换    System.out.println("name:" + name);}

参数化类型

泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

//List 接口的定义public interface List<E> extends Collection<E>

在List接口中采用泛型化定义之后,<E>中的E表示类型形参,可以接收具体的类型实参,并且此接口定义中,凡是出现E的地方均表示相同的接受自外部的类型实参。

在泛型接口、泛型类和泛型方法的定义过程中,我们常见的如T、E、K、V等形式的参数常用于表示泛型形参,用于接收来自外部使用时候传入的类型实参。

推荐名称:
K ——键,比如映射的键。
V ——值,比如 List 和 Set 的内容,或者 Map 中的值。
E ——异常类。
T ——泛型。

泛型实例的具体类型

ArrayList a = new ArrayList();ArrayList<Integer> b = new ArrayList<Integer>();//ArrayList<Number> c = b; // 编译即报错ArrayList<Number> c = new ArrayList<Number>();Class c1 = a.getClass();Class c2 = b.getClass();Class c3 = b.getClass();System.out.println(c1); //class java.util.ArrayListSystem.out.println(c2); //class java.util.ArrayListSystem.out.println(c3); //class java.util.ArrayListSystem.out.println(c1 == c2); //trueSystem.out.println(c2 == c3); //true/*由上可见,【编译时】认为,ArrayList<Number> 和 ArrayList<Integer> 是两个类型,甚至没有父子关系。而【运行时】的类型则都是 class java.util.ArrayList*/

在使用泛型类时,虽然传入了不同的泛型实参,但并没有真正意义上生成不同的类型,传入不同泛型实参的泛型类在内存上只有一个,即还是原来的类型(本实例中为ArrayList),当然,在逻辑上我们可以理解成多个不同的泛型类型。

究其原因,在于Java中的泛型这一概念提出的目的,导致其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦除,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。

对此总结成一句话:泛型类型在【编译阶段】逻辑上可以看成是多个不同的类型,【运行阶段】实际上都是相同的类型。

类型通配符

上节代码中提到“【编译时】认为,ArrayList<Number> 和 ArrayList<Integer> 是两个类型,甚至没有父子关系。”

List<Integer> intList = newArrayList<Integer>();List<Number> numberList = intList; //invalidnumberList.add(new Float(3.1415f));

如果允许父子关系,以上代码正确执行,就会导致intList中插入了非Integer的值,这违反了泛型提供的类型安全机制

实际编程中,我们需要一个在逻辑上可以用来表示同时是ArrayList<Number> 和 ArrayList<Integer>的父类的一个引用类型(如:ArrayList<?>),由此,类型通配符应运而生。

类型通配符上限通过形如ArrayList<? extends Number>形式定义,相对应的,类型通配符下限为ArrayList<? super Integer>形式

总结与注意事项

总结
(1)泛型的精髓就是“参数化类型”
(2)泛型只在编译时起作用
(3)泛型的通配符<?>可以看作相应泛型的父类使用。

注意事项
(1)泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
(2)泛型的类型参数可以有多个。
(3)不能对确切的泛型类型使用instanceof操作。如下面的操作是非法的,编译时会出错。
(4)不能创建一个确切的泛型类型的数组。

参考博文

http://www.cnblogs.com/lwbqqyumidi/p/3837629.html 【初级】(泛型总结-其中关于通配符的反证法举例有问题)
http://blog.csdn.net/seu_calvin/article/details/52230032 【初级】(java泛型详解)
http://blog.csdn.net/caihuangshi/article/details/51278793【进阶】(java泛型详解)