但行好事  莫问前程

泛型系列(六):泛型与数组

Java5的泛型有一个很重要的设计原则是,如果一段代码在边缘的时候没有提出”[unchecked]未经检查的转换”警告,则程序在运行时不会引发ClassCastException异常,正是基于这个原因,所以数组元素的类型不能包含类型变量或者类型形参,除非是无上限的类型通配符。但是可以声明元素类型包含类型变量或者类型形参的数组。也就是说,只能声明List<String>[]形式的数组,但不能创建ArrayList<String>[10]这样的数组对象。
假设java支持创建ArrayList<String>[10]这样的数组对象,则有如下程序:

//下面的代码实际上是不允许的
List<String>[] lsa=new List<String>[10];
//强制类型转换为一个Object数组
Object[] oa = (Object)lsa;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
//将List<Integer>对象作为oa的第二个元素
//下面代码没有任何警告
oa[1]=li;
//下面代码也不会有任何警告,但将引发ClassCastException
String s = lsa[1].get(0);  //①

在上面代码中,如果粗体字代码是合法的,经过中间系列的程序运行,势必在处引发运行时异常,这就违背了java泛型的设计原则。如果将程序改为如下形式:

       //下面的代码编译时有"unchecked 未经检查的转换"警告
        List<String>[] lsa=new ArrayList[10];
        //强制类型转换为一个Object数组
        Object[] oa = (Object[])lsa;
        List<Integer> li = new ArrayList<Integer>();
        li.add(new Integer(3));
        //将List<Integer>对象作为oa的第二个元素
        //下面代码没有任何警告
        oa[1]=li;
        //下面代码也不会有任何警告,但将引发ClassCastException
        String s = lsa[1].get(0);  //①

上面代码声明了List<String>[]类型的数组变量,这是允许的;但是不允许创建List<String>[]类型的对象,所以创建了一个类型为ArrayList[10]的数组对象,这也是允许的。只是把ArrayList[10]对象赋值给List<String>[]变量时会有编译警告”unchecked 未经检查的转换”,即编译器并不保证这段代码是类型安全的。上面代码同样会在处引发运行时异常,但因为编译器已经提出了警告,所以完全可能出现这种异常。

Java允许创建无上限的通配符泛型数组,例如new ArrayList[10],因此也可以将第一段代码改为使用无上限的通配符泛型数组,在这种情况下,程序不得不进行强制类型转换。如下代码所示:

 
      List<?>[] lsa=new ArrayList<?>[10];
        Object[] oa = (Object[])lsa;
        List<Integer> li = new ArrayList<Integer>();
        li.add(new Integer(3));
        oa[1]=li;
        //下面代码引发ClassCastException
        String s = (String)lsa[1].get(0);

编译上面代码不会发出任何警告,运行上面程序将在最后一行引发ClassCastException异常。因为程序需要将lsa的第一个数组元素的第一个集合元素强制类型转换为String类型,所以程序应该自己通过instanceof运算符来保证它的数据类型。即改为如下形式:

 
       List<?>[] lsa=new ArrayList<?>[10];
        Object[] oa = (Object[])lsa;
        List<Integer> li = new ArrayList<Integer>();
        li.add(new Integer(3));
        oa[1]=li;
        Object target = lsa[1].get(0);
        if(target instanceof String){
            //下面代码安全了
            String s=(String)target;
        }

与此类似的事,创建元素类型是类型变量的数组对象也将导致编译错误。如下代码所示:

 
T[] makeArray(Collection<T> coll){
        //下面代码将导致编译错误
        return new T[coll.size()];
    }

因为类型变量在运行时并不存在,所以编译器无法确定实际类型是什么。

打赏
欢迎关注人生设计师的微信公众账号
公众号ID:longjiazuoA

未经允许不得转载:人生设计师 » 泛型系列(六):泛型与数组

分享到:更多 ()

人生设计师-接受不同的声音

联系我关于我