Java 为什么强制转换对象[]数组是错误的?
我对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? 虽然我找到了一个解决方案,但我仍然无法理解是什么阻止了创建通用数
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[]
是你真正可以做的事情。这正是困扰我很久的东西。如果你能澄清这一点,我将非常高兴。”“因为