ArrayList实现中的通用数组

时间:2013-08-17 17:46:16

标签: java arrays generics collections

如何使以下代码完全通用?

为什么我不被允许写:

private E[]store = new E[length];

import java.util.Arrays;
public class MyArrayList<E> {
    private int size = 0;
    private int length = 10;

    private Object [] store = new Object[length];
        public E get(int index){
        return (E)store[index];
    }

    public void add(E item){
        if(size >= store.length -5){
            increment(store);
        }
        store[size++] = item;
    }

    private <T> void increment(T[] store2) {
        store = Arrays.copyOf(store2, store2.length * 2);
    }

    public int size(){
        return size;
    }
}

2 个答案:

答案 0 :(得分:2)

您只能声明其组件类型为类型参数的数组变量,但不能创建相应的数组对象。由于类型擦除,E的类型在运行时是未知的。编译器不知道如何创建未知组件类型的数组。

同样,您无法创建具体参数化类型的数组。

解决方法是使用Array.newInstance方法:

Class<E> clazz;
E[] array = (E[])Array.newInstance(clazz, length) ;

但是,这会为您提供未经检查的投射警告,因为Array.newInstance会返回Object,您将其投射到E[]。您可以使用@SuppressWarnings注释来禁止警告。但是,您需要在该方法中传递clazz参数,该参数应该是E类型参数的类类型。


数组和泛型类型之间存在重大差异 - 即,数组具体化(正如@Marko在其答案中所述)。我会在书中Effective Java - Item 29添加一个关于这个主题的段落:

  

这意味着数组知道并强制执行其元素类型   运行。如上所述,如果您尝试将String存储到Long数组中,那么您将会这样做   得到一个ArrayStoreException。相反,泛型是通过擦除实现的   [JLS,4.6]。这意味着它们仅在编译时强制执行其类型约束   时间并在运行时丢弃(或擦除)其元素类型信息。擦除是   什么允许泛型类型与不使用的遗留代码自由互操作   仿制药(第23项)。

     

由于这些基本差异,数组和泛型不会混用   好。例如,创建泛型类型(参数化)的数组是非法的   类型或类型参数。这些数组创建表达式都不合法:new List<E>[]new List<String>[]new E[]。所有这些都将导致通用数组创建   编译时的错误。

答案 1 :(得分:2)

与泛型类型参数不同,数组元素类型是一个具体化的实体。换句话说,new Integer[]会创建一种与new Double[]不同的对象。与此相反,new ArrayList<Integer>()创建与new ArrayList<Double>()完全相同的对象。

由于泛型类型参数已从运行时代码中删除,因此JVM无法实例化您想要的正确类型的数组。