zoukankan      html  css  js  c++  java
  • EffectiveJava(25)泛型和数组的使用取舍及规范

    泛型和数组
    泛型: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
    
    总结:数组和泛型有着非常不同的类型规则.数组是协变且可以具体化的;泛型是不可变且可以被擦除的.因此,数组提供了运行时的类型安全,但是没有编译时的类型安安全,反之,对于泛型也一样.一般来说,数组和反省不能很好地混合使用.如果你发现自己将它们混合使用,并且得到了编译时错误或警告,那么就应该用列表代替数组!
    
  • 相关阅读:
    ASP.NET MVC路由模块
    线程安全的单例模式
    MVC自带表单效验
    MSsql 中 in 语法排序的说明
    Web.Config配置错误页面处理
    WCF基本应用
    .NET微信自定义分享标题、缩略图、超链接及描述的设置方法
    .NET微信通过授权获取用户的基本信息
    C#中获取服务器IP,客户端IP以及网卡物理地址
    .NET获取客户端、服务器端的信息
  • 原文地址:https://www.cnblogs.com/qwop/p/6637284.html
Copyright © 2011-2022 走看看