为什么我不能创建泛型类型的数组?

时间:2012-07-25 12:26:42

标签: java language-design language-details

简而言之,这不会编译:

public <A> void test() {
    A[] temp = new A[]{};
}

是因为向后兼容性问题,还是语言设计中的一些根本兼容性呢?

5 个答案:

答案 0 :(得分:7)

底线是表示数组的类必须知道组件类型。因此Class对象上的方法:

public Class<?> getComponentType()
Returns the Class representing the component type of an array. If this class does not represent an array class this method returns null.

所以当你尝试:

 A[] a = new A[0];

在编译时,很明显我们不知道类型,因为它是一个通用参数。在运行时,由于类型擦除,我们不知道类型。因此,实例化数组是不可能的。

将上述陈述视为等同于:

 A[] a = (A[])Array.newInstance(???, 0);

由于类型擦除,我们无法在运行时获得A类。

有人问为什么不将编译器缩减为Object []或Number []或类似的东西?

这是因为根据组件类型将返回不同的Class。所以:

 new Object[0].getClass() 
 new Integer[0].getClass()

不是同一个班级。特别是类上的“getComponentType()”方法将返回不同的值。

因此,如果你将它减少到Object []而不是A [],你实际上并没有得到类型A []的东西,你得到的是Object []。 Object []不能被装入Integer []并产生ClassCastException。

答案 1 :(得分:5)

类型erasure是您要查找的字词。它基本上意味着generic信息在编译时被删除。其主要原因是向后兼容性。旧程序仍应在新的java虚拟机上运行。

答案 2 :(得分:3)

在Java中,数组和泛型的类型系统是不兼容的。 有两个主要差异区域:动态与静态类型检查协方差

静态检查泛型:也就是说,编译器确保类型定义是一致的。 “类型擦除”是一种折衷方案,可确保JVM中的向后兼容性。编译后,泛型类型定义不再可用。例如。 List<T>变为List

相反,数组是动态类型检查的。请考虑以下示例:

String strings[] = {"a","b","c"};
Object simple[] = strings;
simple[0] = new Object(); // Runtime error -> java.lang.ArrayStoreException 

协方差是基于内容的容器的继承关系。 给定类型A,B和容器C,如果B是AssignableFrom(A)=&gt; C是Assignable C.

Java中的数组是协变的,在前面的示例中,给定Class<Object>.isAssignableFrom(Class<String>) => Object[] is assignable from String[]

相反,泛型类型在Java中不协变。使用相同的例子:

List<String> stringList = new ArrayList<String>();
List<Object> objectList = stringList; // compiler error - this is not allowed.

鉴于泛型实现的类型擦除,类型信息在转换中会丢失,因此如果您可以创建泛型类型的数组,则会影响动态类型检查。

进一步阅读这些问题的复杂性和影响:Arrays in Java Generics

答案 3 :(得分:1)

这不适用于new A()无法工作的相同(或几乎相同)的原因:您希望编译器知道A的运行时类型,它显然不能知道。如果Java Generics类似于C ++模板,那么工作,其中为包含A的模板的每个实例化生成新代码。

答案 4 :(得分:0)

是的,有一个根本原因,归结为type erasure

请考虑以下代码段:

A[] temp = new A[5];       // Assume this would compile.

Object[] objects = temp;   // This is allowed, since A extends Object.

objects[0] = new String(); // This does *not* throw an ArrayStoreException
                           // due to type erasure since the original type of A
                           // is now Object.

A t = temp[0];             // Now this seemingly innocent line would *fail*.

相关问题: