Java 泛型数组解密

     Java泛型由于只存在于编译时期,实际运行的类型还是Object类型,泛型数组也如下所示:

      例如,我们试图定义一个泛型数组工具类,它可以用于按照顺序存入一个值,和指定位置取一个值,这实际上简易版的ArrayList,主要代码如下所示:

 

     ackage genericArray;

/**
 * 类GenericArray.java的实现描述:
 * @author sweet 2012-6-17 下午7:23:28
 */
public class GenericArray<T> {
    
    private T[] array;
    
    @SuppressWarnings("unchecked")
    public GenericArray(int size){
        this.array=(T[])new Object[size];
    }
    
    public void put(int index,T data){
        array[index]=data;
    }
    
    public T get(int index){
        return array[index];
    }
    
    /**
     * 这个方法会诱发 {@link java.lang.ClassCastException}<br/>
     * 表明无论如何数组的运行类型只能是Object[]类型
     * 
     * @return T[]
     */
    public T[] rep(){
        return array;
    }
    
    public static void main(String[] args){
        GenericArray<Integer> genericArray=new GenericArray<Integer>(10);
        genericArray.put(0, 11);
        genericArray.put(1, 13);
        System.out.println(genericArray.get(0));
        System.out.println(genericArray.get(2));
        try{
            Integer[] integerArray=genericArray.rep();
            System.out.println(integerArray);
        }catch(Exception e){
            System.out.println(e);
        }       
    }
}
 

     这段代码有个问题,就是它在初始化泛型数组的时候,使用了强制转型,这会导致一个编译时期的警告,虽然我们可以使用@SuppressedWarnings("unchecked")来在编译期绕过检查,但不是一个好办法。

      所以下面一段代码对它稍稍改善了下,直接定义Object[]数组,在插入值做向上转型(这个在运行期间可以自动完成),和在取出值时向下转型(这个需要手动强制转型,并且会有编译期警告,但是由于我们只保留了一个可以用于插入值的入口,所以这个问题看上去没那么严重)

     /**

 * 类GenericeArrayOptimization.java的实现描述:<br/>
 * 这个类试图利用Object[]去修复{@link GenericArray#rep()}方法所造成的泛型转换异常
 * @author sweet 2012-6-17 下午7:44:07
 * @see genericArray.GenericArray
 */
public class GenericeArrayOptimization<T> {
    
    private Object[] objectArray;
    
    public GenericeArrayOptimization(int size){
        objectArray=new Object[size];
    }
    
    /**
     * 这里只所以可以强转,是因为{@link GenericeArrayOptimization#put(int, Object)}<br/>
     * 方法放入的对象都是T类型
     * 
     * @param index
     * @return
     */
    @SuppressWarnings("unchecked")
    public T get(int index){
        return (T)objectArray[index];
    }
    
    public void put(int index,T data){
        objectArray[index]=data;
    }
    
    /**
     * 试图返回泛型数组的泛型<br/>
     * 调用该方法会抛出{@link java.lang.ClassCastException}
     * 
     * @return
     */
    @SuppressWarnings("unchecked")
    public T[] rep(){
        return (T[])objectArray;
    }
    
    public static void main(String[] args){
        GenericeArrayOptimization<Integer> array=new GenericeArrayOptimization<Integer>(10);
        array.put(0, 11);
        array.put(1, 13);
        System.out.println(array.get(1));
        try{
            //实践证明,这种转换方式还是会抛出类型转换错误
            Integer[] t=array.rep();
        }catch(Exception e){
            System.out.println(e);
        }
    }
}
 

    从以上代码可以看出,没有任何方式可以推翻底层时候的数组类型,它在运行期间只能是Object类型,那么实际上有更好的办法,这个时候java.lang.reflect.Array.newInstance(Class<T> componentType,int length)就起到了作用。

    我们先简单的看下JDK对这个方法的说明:

     public static Object newInstance(Class<?> componentType,

                                 int... dimensions)
                          throws IllegalArgumentException,
                                 NegativeArraySizeException
 

       创建一个具有指定的组件类型和维度的新数组。如果 componentType 表示一个非数组类或接口,则新数组具有 dimensions.length 维度,并且将 componentType 作为其组件类型。如果 componentType 表示一个数组类,则新数组的维数等于 dimensions.lengthcomponentType 的维数的总和。在这种情况下,新数组的组件类型为 componentType 的组件类型。

        新数组的维数不能超过该实现所支持的数组维数(通常为 255)。改造后的代码如下所示,用这个方法就可以创建我们真正需要的实际类型的数组。很可惜,在JDK类库里面,到处充斥着第二种方法的影子,不停的向上转型和向下转型。

       /**

 * 类GenerayArrayWithTypeToken.java的实现描述:<br/>
 * 由{@link java.lang.reflect.Array#newInstance(Class, int)}<br/>
 * 来实现泛型数组的返回,可参考{@link GenericeArrayOptimization#rep()}
 * @author sweet 2012-6-24 上午11:28:02
 */
public class GenerayArrayWithTypeToken<T> {
    
    private T[] array;

    @SuppressWarnings("unchecked")
    public GenerayArrayWithTypeToken(Class<T> componentType,int length){
        array=(T[])Array.newInstance(componentType, length);
    }
    
    public void put(int index,T data){
        this.array[index]=data;
    }
    
    public T get(int index){
        return this.array[index];
    }
    
    public T[] rep(){
        return this.array;
    }
    
    public static void main(String[] args){
        GenerayArrayWithTypeToken<Integer> genericArray=new GenerayArrayWithTypeToken<Integer>(Integer.class,10);
        genericArray.put(0, 11);
        genericArray.put(1, 31);
        System.out.println(Arrays.toString(genericArray.rep()));
    }
}
 

 

 

 

 

 






posted @ 2012-06-24 20:39  老去的JAVA程序员  阅读(252)  评论(0编辑  收藏  举报