以下类使用了泛型:
public class Container <E>{
private List<E> elements=new ArrayList<E>();
public void addAll(List<E> list){
elements.addAll(list);
}
public void removeAll(List<E> list){
list.addAll(elements);
elements.clear();
}
public static <T> List<T> union(List<? extends T> list1,List<? extends T> list2){
return null;
}
}
使用以下测试代码将报错:
List<Integer> list1=Arrays.asList(1,2,3);
Container<Number> container=new Container<Number>();
container.addAll(list1);//编译时报错
以上测试代码,因为使用了Container<Number>声明,addAll()将仅接受List<Number>类型的参数值,所以当传入一个List<Integer>类型的参数将报错,尽管Integer是Number的子类
可以使用泛型通配符增加泛型方法的适应性,其基本原则为PECS(producer-extends,consumer-super),以上例,addAll()传入的list参数将提供数据给container对象,所以此list对象相对container来说是producer。同理,removeAll()传入的list参数将使用container移除的对象,所以此list是consumer。根据以上原则,修改方法如下:
public void addAll(List<? extends E> list){
elements.addAll(list);
}
public void removeAll(List<? super E> list){
list.addAll(elements);
elements.clear();
}
所有Comparable、Comparator都是Consumer,在使用此接口时应使用如下声明:
public <T extends Comparable<? super T>> T max(List<T> list){
return null;
}
以下测试union()的代码将报错,传入的参数分别是List<Integer>, List<Double>类型,导致编译器不知道应使用哪种参数类型(为什么编译器不从返回结果的类型List<Number>获取实际参数类型?)
List<Integer> list1=Arrays.asList(1,2,3);
List<Double> list2=Arrays.asList(4.0d,5.0d,6.0d);
List<Number> list=Container.union(list1, list2);//编译时报错
可以进行如下修改,显式指定编译器使用的实际参数类型为Number:
List<Number> list=Container.<Number>union(list1, list2);
使用泛型可以限制“容器”所能存储的元素的类型,如List<E>的限制容器List里仅能存放类型为E的元素。对应类似Map类型的容器,可以对key使用泛型,如下接口key的类型为Class<T>,而value为T,即value.class类型与key相同,这称为typesafe heterogeneous container:
注:可以调用Class.asSubclass() 进行类型转换
public class Favorites {
public <T> void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);
}
具体实现类:
public class Favorites {
private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();
public <T> void putFavorite(Class<T> type, T instance) {
if (type == null)
throw new NullPointerException("Type is null");
favorites.put(type, type.cast(instance));//避免放入与type类型不同的对象
}
public <T> T getFavorite(Class<T> type) {
return type.cast(favorites.get(type));
}
}