Java 为什么强制转换对象[]数组是错误的?

Java 为什么强制转换对象[]数组是错误的?,java,arrays,object,generics,Java,Arrays,Object,Generics,我对Java中的泛型编程非常陌生 我不明白为什么不能创建泛型类型的数组 T[] a = new T[size]; //why does this give an error? 如果泛型类型意味着泛型占位符T将在运行时被类名替换,那么是什么阻止我们创建具有泛型引用的数组 经过一番搜索,我找到了一个解决方法 T[] a = (T[])new Object[size]; //I don't get how this works? 虽然我找到了一个解决方案,但我仍然无法理解是什么阻止了创建通用数

我对Java中的泛型编程非常陌生

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

T[] a = new T[size]; //why does this give an error?
如果泛型类型意味着泛型占位符
T
将在运行时被类名替换,那么是什么阻止我们创建具有泛型引用的数组

经过一番搜索,我找到了一个解决方法

T[] a = (T[])new Object[size];   //I don't get how this works?
虽然我找到了一个解决方案,但我仍然无法理解是什么阻止了创建通用数组。 假设我创建了一个返回对象数组的函数

public Object[] foo(){
        return new Object[12];
}
然后打电话

String[] a = (String[])foo();
给出一个
ClassCastException
。但是为什么呢? 它看起来和我将对象数组转换为t数组的第一行代码类似吗

 T[] a = (T[])new Object[size];

如果这一切顺利,为什么不呢

在处理数组时,有几件事需要注意

首先,数组被认为是协变的;也就是说,类型化数组将维护其继承链。因此,
Integer[]
对象[]
,其方式与
Integer
对象的方式相同

这就是上一个例子失败的原因。您想通过
foo
对象[]
强制转换为
字符串[]

String[] a = (String[])foo();
对象[]
永远不会是
字符串[]
,因为
对象
不是
字符串
(但情况总是相反)

其次,数组和泛型不能很好地混合。泛型被认为是不变的;也就是说,他们不会保持他们的继承链。
列表
不被视为与
列表
相同

至于您的特定示例失败的原因,这是由于编译时的类型擦除。数组需要在编译时知道它们的具体类型,如果没有这些信息,它们就不能被实例化。由于泛型不存储这些信息,因此不能像实例化非泛型数组那样实例化泛型数组

也就是说,您必须使用演员表:

T[] a = (T[]) new Object[size];

,因为它涵盖了处理这些问题时需要知道的大部分要点。

部分要点是从另一个角度看待它。您不能执行
(字符串[])新建对象[10]
;因为
对象
数组不是
字符串
数组。因为

String[] array = new String[10];
array[0] = "foo";
String foo = array[0];
很好,但是

Object[] objectArray = new Object[10];
objectArray[0] = 10;
String[] stringArray = (String[]) objectArray;
String foo = stringArray[0];
…正在尝试将一个
整数
分配给一个
字符串
,这首先是不允许的。因此,当您将
对象[]
强制转换为
字符串[]
时,此代码将失败。该代码必须在某个地方抛出一个
ClassCastException

甚至在泛型发明之前,Java也是如此。先接受这一切。然后转到泛型

现在,Java泛型的实现方式意味着,当您编译代码时,
T
被静默地重写为
Object
。因此,
T[]数组=(T[])新对象[10]
被静默地允许,因为它实际上被重写为
Object[]数组=新对象[10]
。但一旦你把它拿出来,事情就不对劲了。比如说,

private static <T> T[] newArray() {
   return (T[]) new Object[10];
}
private static T[]newArray(){
返回(T[])新对象[10];
}
如果调用
String[]array=newArray()
,您将在调用站点得到一个
ClassCastException
,而不是在
newArray()中。这就是为什么Java会在
(T[])新对象[10]
上给您一个警告,这个警告很可能会在以后导致真正的
类异常


一般来说,不要混合使用数组和泛型。解决这一切的方法是正确地使用
列表。

数组在运行时知道它们的类型。
String[]
知道它是一个
String
s的数组

与此相反,泛型类型参数在运行时被擦除,因此运行时的
列表
只是一个
列表

由于类型参数
T
在运行时不可用
newt[10]
(未编译),因此不可能创建真正的
T[]

事实并非如此

T[] a = (T[])new Object[size];
无法抛出异常。它可以。Louis Wasserman的示例表明,它可以在调用站点引发异常,但该行也可以直接引发异常。比如说

public static void main(String[] args) {
    foo();
}

static <T extends Number> void foo() {
    T[] array = (T[]) new Object[42];
}
Array.newInstance(clazz, length);

您在一个问题中总共问了六个问题:)@SURESH ATTA我觉得它们都是相关的:/@Djack:generic type并不意味着“在运行时,泛型占位符T将被类名替换”。它在运行时之前被
对象
替换。java泛型与C++模板不同。你的答案是有用的,但是如果<代码> T <代码>重写为<代码>对象< /代码>,那么当我创建一个实例时会发生什么?像
Hello=newhello()
一样,
T[]
是否只保留
Object[]
,而不是变成
String[]
?是的。是的,
T[]
仅保留
Object[]
,然后当您试图将其作为
字符串[]
取出时,会得到一个
ClassCastException
。Java将在任何您提取泛型并将其分配给实际类型的地方插入类型转换。因此,如果在编译时泛型占位符被重写为
Object
,那么说
T[]=new T[size]
应该不会有问题,因为它将转换为
Object[]=new Object[size]
。但是编译器却给出了一个错误?不,您根本无法编写
新的t[size]
,因为编写编译器是为了强制您仅使用实际类型创建数组,因此您可以编写
(t[])新对象[n]
,但随后会收到一条警告。Java编译器不允许你假装
newt[]
是你真正可以做的事情。这正是困扰我很久的东西。如果你能澄清这一点,我将非常高兴。”“因为