11

简而言之,这不会编译:

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

是因为向后兼容性的问题,还是语言设计中的一些基本因素阻止了它?

4

5 回答 5

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。

于 2012-07-25T12:59:26.880 回答
5

类型擦除是您要查找的词。这基本上意味着通用信息在编译时被删除。造成这种情况的主要原因是向后兼容性。旧程序仍应在新的 java 虚拟机上运行。

于 2012-07-25T12:28:22.543 回答
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 isAssignableFrom(A) => C isAssignable 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.

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

进一步阅读这些问题的复杂性和影响:Java 泛型中的数组

于 2012-07-25T13:16:45.993 回答
1

由于无法工作的相同(或几乎相同)原因,这new A()不起作用:您期望编译器知道A它显然无法知道的运行时类型。如果 Java 泛型类似于 C++ 模板,这A起作用,其中为涉及.

于 2012-07-25T12:34:23.503 回答
0

是的,有一个根本原因,归结为类型擦除

考虑以下代码段:

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*.

相关问题:

于 2012-07-25T12:28:45.033 回答