深入Java泛型
目标
1、掌握Java SE的泛型原理
2、泛型高级应用
3、使用泛型集合API操纵对象数据
为什么需要泛型?
在Java SE 5.0以前操作集合的缺点:
从集合中取出对象,需要执行类型转换操作:
ArrayList files = new ArrayList();
. . .
String filename = (String) files.get(0);
由于没有类型检查,可以向集合添加任意对象,例如添加一个文件对象,但get方法取出的File对象转换为String会产生运行错误:
files.add(new File(". . ."));
基于泛型的解决方案:
泛型提供了类型参数
只能将String类型对象存入集合,不能存储“大象”,“File”等
ArrayList<String> files = new ArrayList<String>();
编译器可以发现如下错误:
files.add(new File(". . ."));
取出对象的类型为String,无需执行类型转换
String filename = files.get(0);
定义一个泛型类
Pair类具有两个成员,类型待定
使用private T first表示first的类型为参数T
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; }
}
实现通用的求极值算法
编写一个泛型方法,能够对数组求最大值和最小值
class ArrayAlg {
public static <T extends Comparable> Pair<T> minmax(T[ ] a) {
if (a == null || a.length == 0) {
return null;
}
T min = a[0];T max = a[0];
for (int i = 1; i < a.length; i++) {
if (min.compareTo(a[i]) > 0) {min = a[i];}
if (max.compareTo(a[i]) < 0) { max = a[i];}
}
return new Pair<T>(min, max);
}
}
使用泛型方法
创建一个日历的数组,求出最大和最小的日期
Pair<GregorianCalendar> mm 使用GregorianCalendar为Pair<T>传递类型参数
Java.util.GregorianCalendar实现接口java.lang.Comparable<T>
GregorianCalendar[ ] birthdays = {
new GregorianCalendar(1906, Calendar.DECEMBER, 9),
new GregorianCalendar(1815, Calendar.DECEMBER, 10),
new GregorianCalendar(1903, Calendar.DECEMBER, 3),
new GregorianCalendar(1910, Calendar.JUNE, 22),
};
Pair<GregorianCalendar> mm = ArrayAlg.minmax(birthdays);
System.out.println("min = " + mm.getFirst().getTime());
System.out.println("max = " + mm.getSecond().getTime());
泛型在使用中还有一些规则和限制:
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上成为“有界类型”。
5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(java.lang.String);