泛型程序设计(Generic programming) 意味着编写的代码可以被很多不同类型的对象所重用.

类型参数的好处:

在 Java 中增加范型类之前,泛型是用继承实现的.他存在两个问题:

  1. 获取一个值得时候必须进行强制类型转换.
  2. 没有错误检查,可以向数组列表中添加任何类的对象.

类型参数的出现使得程序有更好的可读性和安全性.

定义简单的泛型类

一个泛型类就是具有一个或多个类型变量的类.在下面这个类中,只关注泛型的话,就不会为数据储存的细节烦恼.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Pair<T>
{
private T first;
private T second;
public Pair() { first = null; second = null; }
public Pair(T first, T second) { this.first = first; this.second = second;}
public T getFirst() { return first; }
public T getSecond() { return second; }
public void setFirst(T newValue) { first = newValue; }
public void setSecond(T newValue) { second = newValue; }
}

类定义中的类型变量指定方法的返回类型以及域和局部变量的类型.例如:

private T first;

用具体的类型替换类型变量就可以实例化泛型类型.例如:

Pair<String>

可以将结果想象成带有构造器的普通类:

1
2
Pair<String>()
Pair<String>(String, String)

和方法

1
2
3
4
String getFirst()
String getSecond()
void setFirst(String)
void setSecond(String)

泛型类可以看做普通类的工厂.

类型变量使用大写形式,且比较短,这是很常见的.在 Java 库中,使用变量 E 表示集合的元素类型, K 和 V 分别表示表的关键字与值的类型.T (需要时还可以用临近的字母 U 和 S) 表示”任意类型”.

泛型方法

定义一个带有类型参数的简单方法:

1
2
3
4
5
6
7
class ArrayAlg
{
public static <T> T getMiddle(T...a)
{
return a[a.length / 2];
}
}

类型变量放在修饰符的后面,返回类型的前面.
泛型方法可以定义在普通类中,也可以定义在泛型类中.
当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型:
String middle = ArrayAlg.<String>getMiddle("John","Q.","public");

泛型代码和虚拟机

虚拟机没有泛型类型对象,所有对象都属于普通类.

类型擦除

无论何时定义一个泛型类型,都自动提供了一个相应的原始类型( raw type ).原始类型的名字就是删去类型参数后的泛型类型名.擦除( erased )类型变量,并替换为限定类型(无限定的变量用 Object).

例如, Pair 的原始类型如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Pair
{
private Object first;
private Object second;
public Pair(Object first, Object second)
{
this.first = first;
this.second = second;
}
public Object getFirst() { return first; }
public Object getSecond() { return second; }
public void setFirst(Object newValue) { first = newValue; }
public void setSecond(Object newValue) { second = newValue; }
}

因为 T 是一个无限定的变量,所以直接用 Object 替换.结果是一个普通的类,就好像泛型引入 Java 语言之前已经实现的那样.

在程序中可以包含不同类型的 Pair ,例如, Pair 或 Pair.而擦除类型后就变成原始的 Pair 类型了.

约束与局限性

  • 不能用基本类型实例化类型参数
  • 运行时类型查询只适用于原始类型
  • 不能创建参数化类型的数组
  • Varargs 警告
  • 不能实例化类型变量
  • 不能构造泛型数组
  • 泛型类的静态上下文中类型变量无效
  • 不能抛出或捕获泛型类的实例
  • 可以消除对受查异常的检查
  • 注意擦除后的冲突