泛型和数组
泛型:1.泛型是不可变的.对于任意两个不同类型Type1,type2;List既不是List的子类型,也不是List的超类型
2.泛型是通过擦除来实现的.故泛型只在编译时强化它们的信息,并在运行时丢弃(擦除)他们的元素类型信息
2.a:擦除:使泛型可以与没有使用泛型的代码随意进行互用
数组:1.数组是协变的.如果Sub为Super的子类型,那么Sub[]就是Super[]的子类型
2.数组是具体化的,这表明数组会在运行时才知道并检查他们的元素类型约束
因此,泛型和数组不能很好的进行结合使用,创建泛型数组是非法的,因为他违背了泛型系统提供的基本保证.但后面我们会给出这条的解决方案.
//cannot create a generic array of List<String>
//ClassCastException
List<String>[] stringLists = new List<String>[1];
/List<Integer> initList = Arrays.asList(42);
将List<String>数组保存到一个Object数组变量中,由于数组的协变性,合法
//Object[] objects = stringLists;
//将List<String>保存到Object数组里唯一的元素中,因为泛型是通过擦除实现的,合法 --List<String>运行时是List
objects[0] = initList;
String str = stringList[0].get(0);
当你得到泛型数组创建错误时,最好的解决办法通常是优先使用集合类型List,而不是数组类型E[].这样可能会损失一些性能或者简洁性,但是有更高的类型安全性和互用性
如:
//没有泛型时的代码
static Object reduce(List list,Function f,Object initVal){
synchronized(list){
Object result = initVal;
for(Object o:list)
result = f.apply(result,o);
}
}
inteface Function(){
Object apply(Object arg1,Object arg2);
}
//利用List的toArray方法在持有锁的时候修改reduce方法来复制列表中的内容,也可以备份减法
static Object reduce(List list,Function f,Object initVal){
Object[] snapshot = list.toArray();
Object result = initVal;
for(E e:snapshot){
result = f.apply(result,e);
}
return result;
}
//如果使用泛型定义接口,那么就需要用列表代替数组
inteface Function<T>(){
T apply(T arg1,T arg2);
}
----->>>>修改过后的static
static <E> E reduce(List<E> list,Function<E> f,E initVal){
List<E> snapshot;
synchronized(list){
snapshot = new ArrayList<E>(list);
}
E result = initVal;
for(E e:snapshot){
result = f.apply(result,e);
}
return result;
}
虽然这个版本代码比较冗长,但是可以确保不会产生ClassCastException
总结:数组和泛型有着非常不同的类型规则.数组是协变且可以具体化的;泛型是不可变且可以被擦除的.因此,数组提供了运行时的类型安全,但是没有编译时的类型安安全,反之,对于泛型也一样.一般来说,数组和反省不能很好地混合使用.如果你发现自己将它们混合使用,并且得到了编译时错误或警告,那么就应该用列表代替数组!