定义简单的泛型类:
public class Pair<T>{
private T first;
private T second;
public T getFirst(){ return first; }
public T getSecond(){ return second; }
public void setFirst(T newVal){ first = newVal; }
public void setSecond(T newVal){ second = newVal; }
}
Pair类引入一个新的类型变量,用尖括号(<>)括起来并放到类名的后面。泛型类可以有多个类型变量:
public class Pair<T,U>{...}
使用时,用具体的类型替换类型变量就可以实例化泛型类型:
Pair<String> p = new Pair<String>();
//Java SE7版本及以后,构造函数中可以省略泛型类型
Pair<String> p = new Pair<>();
换句话说,泛型类可以看作是普通类的工厂。
泛型方法:
泛型方法可以定义在普通类中,也可以定义在泛型类中。
class ArrayAlg{
//定义泛型方法
public static <T> T getMiddle(T[] a){
return a[a.length/2];
}
}
//调用泛型方法
String middle = ArrayAlg.<String>getMiddle("John","Q.","Public");
//方法调用中也可以省略类型参数
String middle = ArrayAlg.getMiddle("John","Q.","Public");
类型变量的限定:
有时候,类或方法需要对类型变量进行约束。如我们要实现一个泛型比较方法,那么只有实现了Comparable接口的类才可以进行比较。变量限制的语法如下:
public static <T extends Comparable> T min(T[] a){...}
现在,泛型的min()方法只能被实现了的Comparable接口的类的数组调用,否则会产生一个编译错误。
<T extends BoundingType>表示T应该是绑定类型的子类型,T和绑定类型可以是类,也可以是接口。
一个类型变量或通配符可以有多个限定,例如:
<T,U extends Comparable & Serializable>
限定类型用“&”分隔,类型变量用逗号分隔。
泛型类型的继承规则:
我们假设Manager(经理)是Employee(雇员)的一个子类,那么Pair<Manager>是Pair<Employee>的子类吗?不是!下面这样编写代码会得到一个错误:
Manager[] topHon = ...;
Pair<Employee> result = ArrayAlg.minmax(topHon);//错误
无论S与T是什么关系,通常Pair<S>与Pair<T>没有什么联系。
不要泛型和Java继承搞混,下面这样的代码显然正确:
Manager[] managerBuddies = {ceo, cfo}
Employee[] employeeBuddies = managerBuddies; //正确
永远可以将参数化类型转换为一个原始类型(因为类型擦除,见下一篇博客)。但要当心转换后可能会产生类型错误(类型不匹配但不会报错),例如:
Pair<Manager> managerBuddies = new Pair<>(ceo,cfo);
Pair rawBuddies = managerBuddies;
rawBuddies.setFirst(new File("huo");//很明显类型错误,但只会得到一个警告而不是错误
泛型类可以扩展或实现其他泛型类,这一点和普通类没有任何区别。例如ArrayList<T>实现了List<T>接口,一个ArrayList<Manager>可以被转化为一个List<Manager>。
泛型会有一些约束和限制,具体情况下篇讨论。
下一篇:泛型的约束和限制