如何使以下代码完全通用?
为什么我不被允许写:
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;
}
}
答案 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无法实例化您想要的正确类型的数组。