Java不允许我们这么做的原因是什么

private T[] elements = new T[initialCapacity];

我可以理解。net不允许我们这样做,因为在。net中,值类型在运行时可以有不同的大小,但在Java中,所有类型的T都将是对象引用,因此具有相同的大小(如果我错了请纠正我)。

原因是什么?


当前回答

正如其他人已经提到的,你当然可以通过一些技巧来创造。

但不建议这样做。

因为类型擦除,更重要的是数组中的协方差,它允许子类型数组被赋给超类型数组,这迫使你在试图取回值时使用显式类型强制转换,导致运行时ClassCastException,这是泛型试图消除的主要目标之一:在编译时进行更强的类型检查。

Object[] stringArray = { "hi", "me" };
stringArray[1] = 1;
String aString = (String) stringArray[1]; // boom! the TypeCastException

一个更直接的例子可以在Effective Java: Item 25中找到。


协方差:如果S是T的子类型,则类型S[]的数组是T[]的子类型

其他回答

如果我们不能实例化泛型数组,为什么语言有泛型数组类型?没有对象的类型有什么意义呢?

我能想到的唯一原因是varargs - foo(T…)。否则,它们可以完全删除泛型数组类型。(好吧,他们真的不需要为可变参数使用数组,因为在1.5之前不存在可变参数。这可能是另一个错误。)

所以这是一个谎言,你可以实例化泛型数组,通过varargs!

当然,泛型数组的问题仍然存在,例如。

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!
}

我们可以用这个例子来实际演示泛型数组的危险。

另一方面,我们已经使用泛型变参数10年了,现在还没有崩溃。所以我们可以说问题被夸大了;这没什么大不了的。如果允许显式的泛型数组创建,我们会到处都有bug;但我们已经习惯了擦除的问题,我们可以接受它。

我们可以用foo2来反驳这种说法,即规范让我们避免了他们声称让我们避免的问题。如果Sun在1.5上有更多的时间和资源,我相信他们可以达成一个更令人满意的解决方案。

肯定有一个好方法(可能是使用反射),因为在我看来,这正是数组列表。toArray(T[] a)可以。我引用:

public <T> T[] toArray(T[] a) 返回一个数组,其中包含所有 此列表中的元素按正确顺序排列;的运行时类型 返回的数组是指定数组的数组。如果列表符合 指定的数组,则在其中返回。否则,新数组为 的运行时类型分配 这个列表。

因此,一种方法是使用这个函数,即创建一个数组中你想要的对象的数组列表,然后使用toArray(T[] a)来创建实际的数组。不会很快,但你没提你的要求。

有人知道toArray(T[] a)是如何实现的吗?

试试这个:

List<?>[] arrayOfLists = new List<?>[4];

主要原因是Java中的数组是协变的。

这里有一个很好的概述。

Oracle教程:

You cannot create arrays of parameterized types. For example, the following code does not compile: List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile-time error The following code illustrates what happens when different types are inserted into an array: Object[] strings = new String[2]; strings[0] = "hi"; // OK strings[1] = 100; // An ArrayStoreException is thrown. If you try the same thing with a generic list, there would be a problem: Object[] stringLists = new List<String>[]; // compiler error, but pretend it's allowed stringLists[0] = new ArrayList<String>(); // OK stringLists[1] = new ArrayList<Integer>(); // An ArrayStoreException should be thrown, // but the runtime can't detect it. If arrays of parameterized lists were allowed, the previous code would fail to throw the desired ArrayStoreException.

对我来说,这听起来很软弱。我认为任何对泛型有充分理解的人,都完全可以理解,甚至期望,在这种情况下ArrayStoredException不会被抛出。