当我遇到一个小谜团时,我正在发布另一个问题的答案。类定义(从原始提问者中稍作修改)在这里:
public class Playground<T>{
private int pos;
private final int size;
private T[] arrayOfItems;
public Playground(int size){
this.size = size;
pos = 0;
arrayOfItems = (T[]) new Object[size];
}
public void addItem(T item) {
arrayOfItems[pos] = item;
pos++;
}
public void displayItems() {
for(int i = 0;i<pos;i++){
System.out.println(arrayOfItems[i]);
}
}
public T[] returnItems() {
return (T[]) arrayOfItems;
}
}
首先,我们创建一个新的Playground,Playground<String> animals = new Playground<String>(5);
并在其中放入一些动物弦。(狗,猫等)。
神秘之处在于:
Object[] s = animals.returnItems();
for(int i=0; i < s.length; i++) {
System.out.println(s[i]);
}
但这会ClassCastException
在for循环声明中创建一个。
for(int i=0; i < animals.returnItems().length; i++) {
System.out.println(animals.returnItems()[i]);
}
两个Object[]
S和String[]
■找长度变量。为什么在循环声明中使用accessor方法会导致异常?
之所以ClassCastException
不能-强制转换Object[]
为String[]
-是由于编译器在使用泛型时所做的事情。调用时returnItems()
,编译器将强制类型转换为String[]
,因为会returnItems
返回T[]
。编译时的类型擦除表示它返回Object[]
,但既然T
在String
这里,编译器就会将强制转换插入String[]
。但是原始对象arrayOfItems
不是String[]
,而是Object[]
,因此转换失败。
这应该导致在编译过程中产生一个“ unchecked cast”警告,从Object[]
到T[]
。
相反,您需要遵循如何在Java中创建通用数组中的建议。在创建通用数组时。
Class<T>
在构造函数中接受一个,这样您就可以从一开始就调用Array.newInstance
并获取一个T[]
。
@SuppressWarnings("unchecked") // This suppression is safe.
public Playground(int size, Class<T> clazz){
this.size = size;
pos = 0;
arrayOfItems = (T[]) Array.newInstance(clazz, size);
}
然后,您可以animals
通过String.class
以下方式创建:
Playground<String> animals = new Playground<String>(5, String.class);
更新
以下是Object[]
当第二个示例不起作用(length
直接在方法的返回类型上访问字段)时为什么第一个示例起作用(分配给)的合理解释returnItems()
。
第一个例子
Object[] s = animals.returnItems();
for(int i=0; i < s.length;i++) {
System.out.println(s[i]);
}
的JLS,第5.2节,描述了“作业上下文”支配从分配给一个变量的表达式的值时会发生什么。
分配上下文中的转换可能引起的唯一例外是:
- 如果在应用了上述转换之后,结果值是一个对象,它不是变量类型的Erase(第4.6节)的子类或子接口的实例,则为ClassCastException。
这种情况只能由堆污染引起(第4.12.2节)。实际上,当字段的擦除类型或方法的返回类型与未擦除类型不同时,实现仅在访问参数化类型的对象的字段或方法时执行强制转换。
...
编译器无需在String[]
此处插入强制类型转换。length
以后访问该字段时,该变量已经是type Object[]
,因此这里没有问题。
第二个例子
for(int i=0; i < animals.returnItems().length;i++) {
System.out.println(animals.returnItems()[i]);
}
在ClassCastException
这里似乎不是依赖于for
循环; 只需简单打印长度,就会出现此错误:
System.out.println(animals.returnItems().length);
这是一个字段访问表达式,在JLS第15.11.1节中介绍。
标识符以类型T命名一个可访问的成员字段,并且字段访问表达式的类型是捕获转换后的成员字段的类型(第5.1.10节)。
捕获转换将类型捕获为String[]
。编译器String[]
出于与方法调用插入转换相同的原因,必须将转换插入到此处-字段或方法只能存在于捕获的类型上。
因为的类型arrayOfItems
为true Object[]
,所以强制转换失败。
如上所述,创建通用数组可以Array.newInstance
解决此问题,因为String[]
正在创建实际数组。进行此更改后,插入的演员表仍然存在,但是这次成功了。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句