在JDK5.0之前:
public class ArrayList{ public Object get(int i){...} public void add(Object o){...} ... private Object[] elementData; }
这样实现有两问题。首先,当取得一个值的时候必须进行强制类型转换。
ArrayList files = new ArrayList();
...
String filename = (String)names.get(0);
此外,这里没有错误检查。可以向数组列表中添加任何类的对象。
files.add(new File("..."));
对于这个调用,编译和运行都不会出错。然而在其他地方,如果将get的结果强制类型转换为String类型,就会产生一个错误。
JDK5.0提供了一个更好的解决方案:类型参数(type parameter)。ArrayList类有一个类型参数用来指示元素的类型:ArrayList<String> files = new ArrayList<String>();
这将使代码具有更好的可读性。人们一看就知道这个数组列表中包含的是String对象,添加错误的类型会编译报错,取出元素也不需强制类型转换。类型参数的魅力在于,使得程序具有更好的可读性和安全性。
泛型类的自定义:
public class Pair<T>{ private T first; private T second; public Pair(){ first = null; second = null; } public T getFirst(){ return first; } public T getSecond(){ return second; } public void setFirst(T newValue){ first = newValue; } public void setSecond(T newValue){ second = newValue; } }
Pair类引入了一个类型变量T,用尖括号(<>)括起,并放在类名的后面。泛型类可以有多个类型变量,例如:public class Pair<T,U>{...}
泛型方法:
class ArrayAlg{ public static <T> T getMiddle(T[] a){ return a[a.length/2]; } }
这个方法是在普通类中定义的,而不是在泛型类中定义的。注意,类型变量放在修饰符(这里是public static)的后面,返回类型的前面。
当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型:
String[] names = {"John","Q","Public"};
String middle = ArrayAlg.<String>getMiddle(names);(其中<String>可省略)
类型变量的限定:
有时,类或方法需要对类型变量加以约束:
class ArrayAlg{ public static <T extends Comparable> T min(T[] a){ if(a == null || a.length == 0){ return null; } T smallest = a[0]; for(int i=1;i<a.length;i++){ if(smallest.compareTo(a[i])>0){ smallest = a[i]; } } return smallest; } }
类型T要想有compareTo方法,必须继承Comparable接口。
一个类型变量或通配符可以有多个限定,如:T extends Comparable & Serializable。