一、泛型的简单介绍
1. 泛型的引入
JDK 1.5中引入了泛型这个新特性,泛型的本质是参数化类型(Parameterized Types)的应用,也就是指操作的数据类型被指定为一个参数,之后使用到该数据时必须符合指定的类型。这种参数化类型可以在类、接口和方法中使用,分别称为泛型类、泛型接口和泛型方法。
2. 为什么引入泛型
泛型思想在C++模板(Templates)中开始萌芽,在Java还没有泛型的时候,只能通过Object类型是所有类型的父类型和类型强制转换两个特点的配合使用来实现类型泛化。例如在哈希表的存取中,JDK 1.5之前使用HashMap的 get( ) 方法,返回值就是一个Object对象。由于Java中所有的类型都继承自java.lang.Object,那Object可能转换为任何类型的对象。这就带来了一个缺陷:在编译期间,编译器无法检查这个Object的强制转换是否成功,只有程序员和编译期间的虚拟机才知道这个Object到底是什么类型的对象。于是导致运行期间的ClassCastException风险增加。
3. Java的“伪泛型”
在说明Java为什么是“伪泛型”之前,先简单的介绍一下C#的“真实泛型”:
C#泛型是C# 2.0版本中新增的特性,C#无论语言层面还是CLR都提供对泛型的支持,所以C#泛型类或方法编译成Microsoft中间语言(MSIL)时,它依旧包含将其表示为具有类型参数的元数据,也就是说泛型是真实存在的。类型没有变成原生类型,而是通过类型膨胀实现,在运行期生成自己的虚方法和类型数据。所以C# 是“真实泛型”。
而Java的中的泛型只存在于源程序中,在编译后的字节码中,泛型就被替换为原始类型(Raw Type),并且在相应的地方插入了强制转换代码。因此,对于运行期的Java来说,ArrayList<int>与ArrayList<String>就是同一个类。所以说泛型是Java的一颗语法糖,Java中泛型实现的方法称为类型擦除,基于这种方法实现的泛型称为“伪泛型”。
4. 泛型中基本术语
以 ArrayList<E> 和 ArrayList<Integer> 为例:
(1)“ArrayList<E>”称为泛型类型;
(2)ArrayList<E> 中的“E”称为类型变量或类型参数;
(3)“ArrayList<Integer>”称为参数化类型;
(4)ArrayList<Integer>中的“Integer”称为类型参数的实例,或实际类型参数;
(5)ArrayList<Integer>中的“<Integer>”读作“type of Integer”;
(6)“ArrayList”称为原始类型
二、 泛型的使用
1. 泛型类的定义和使用
泛型类(generic class)是具有一个或多个类型变量的类。定义一个泛型类只需在类名后面加上“<>”,然后在尖括号里面加上类型参数。下面是非泛型类和泛型类代码实现的简单对比:
// 非泛型Box类 public class Box { private Object object; public void set(Object object) { this.object = object; } public Object get() { return object; } }
对比
/** * 泛型Box类 * @param <T>是 Box类内部值的类型 */ public class Box<T> { // T stands for "Type" private T t; public void set(T t) { this.t = t; } public T get() { return t; } }