private T[] elements = new T[initialCapacity];
我能理解为什么.NET不允许我们这样做,因为在.NET中,你有值类型,在运行时可以有不同的大小,但是在Java中,所有类型T都将是对象引用,因此具有相同的大小(如果我说错了,请纠正我)。
这是什么原因呢?
private T[] elements = new T[initialCapacity];
我能理解为什么.NET不允许我们这样做,因为在.NET中,你有值类型,在运行时可以有不同的大小,但是在Java中,所有类型T都将是对象引用,因此具有相同的大小(如果我说错了,请纠正我)。
这是什么原因呢?
如果我们不能实例化泛型数组,那么为什么语言会有泛型数组类型呢?拥有没有对象的类型有什么意义?
我能想到的唯一的理由,就是可变参数 - foo(T...)
。否则他们完全可以摒弃泛型数组类型。(嗯,他们在使用可变参数之前并不一定非得使用数组,这可能是另一个错误。)
因此这是个谎言,你可以通过可变参数实例化泛型数组!
当然,泛型数组的问题仍然存在,例如:
static <T> T[] foo(T... args){
return args;
}
static <T> T[] foo2(T a1, T a2){
return foo(a1, a2);
}
public static void main(String[] args){
String[] x2 = foo2("a", "b"); // heap pollution!
}
我们可以利用这个例子来真正展示泛型数组的危险性。
另一方面,我们已经使用了十年的通用可变参数,天空还没有塌下来。所以我们可以认为问题被夸大了;这不是什么大问题。如果允许显式通用数组创建,我们会遇到偶尔的错误;但我们已经习惯了擦除的问题,我们可以应对它。
我们可以指向foo2
来反驳规范防止他们声称防止我们出现问题的说法。如果Sun有更多时间和资源进行1.5的开发,我相信他们可以达到更令人满意的解决方案。
T vals[]; // 可行
但是,您无法实例化T的数组 // vals = new T[10]; // 无法创建T的数组
无法创建T的数组的原因是编译器无法知道要创建什么类型的数组。
肯定有一个好的方法可以解决它(也许使用反射),因为在我看来,这正是ArrayList.toArray(T[] a)
所做的。我引用:
public <T> T[] toArray(T[] a)
返回包含此列表中所有元素的数组,顺序正确;返回数组的运行时类型是指定数组的类型。如果列表适合指定的数组,则返回其中。否则,将使用指定数组的运行时类型和此列表的大小分配新数组。
因此,一种解决方法是使用此函数,即创建要在数组中使用的对象的ArrayList
,然后使用toArray(T[] a)
创建实际数组。这不会很快,但您没有提到您的要求。
那么,有人知道如何实现toArray(T[] a)
吗?
Array.newInstance()
创建该类型的数组。你会发现,在许多问题中都有提到如何使用这种方式创建编译时未知的数组类型。但是 OP 具体询问的是 为什么 不能使用 new T[]
语法,这是另外一个问题。 - newacct正如其他人已经提到的,你当然可以通过 一些技巧 来创建。
但这并不推荐。
因为 类型擦除 和更重要的是数组中的 covariance
,它只允许将子类型数组分配给超类型数组,这迫使你在尝试获取值时使用显式类型转换,导致运行时 ClassCastException
,这是泛型试图消除的主要目标之一:更强的编译时类型检查。
Object[] stringArray = { "hi", "me" };
stringArray[1] = 1;
String aString = (String) stringArray[1]; // boom! the TypeCastException
更直接的例子可以在Effective Java: Item 25中找到。
协变性:如果S是T的子类型,那么类型为S[]的数组是类型为T[]的数组的子类型。
试试这个:
List<?>[] arrayOfLists = new List<?>[4];