庄生晓梦

庄生晓梦迷蝴蝶

博客园 首页 新随笔 联系 订阅 管理

泛型和数组
泛型: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

总结:数组和泛型有着非常不同的类型规则.数组是协变且可以具体化的;泛型是不可变且可以被擦除的.因此,数组提供了运行时的类型安全,但是没有编译时的类型安安全,反之,对于泛型也一样.一般来说,数组和反省不能很好地混合使用.如果你发现自己将它们混合使用,并且得到了编译时错误或警告,那么就应该用列表代替数组!
posted on 2017-03-09 00:29  qwop  阅读(140)  评论(0编辑  收藏  举报