以下类使用了泛型:
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)); } }