5.26-5.29 使用泛型
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));}}
?
?
?
?
?
?
?
?
?