在Java revisited上,代码摘录如下:
class Holder<T>{
private T[] contents;
private int index = 0;
public Holder(int size){
//contents = new T[size]; //compiler error - generic array creation
contents = (T[]) new Object[size]; //workaround - casting Object[] to generic Type
}...}
用于创建泛型数组,但是根据类型擦除(我在java在线教程中查看过),T
在编译的类中结束Object
,因此强制转换(T[])
结束
(Object[])
,似乎没有投射没有区别。
那么铸造的功能或铸造的任何特殊含义是什么?任何提示都很感激。
答案 0 :(得分:4)
演员需要告诉编译器我们这边的分配是好的。否则它会显示编译器错误。
由于类型擦除,类型参数T
在编译时被替换为擦除。
无界类型参数的擦除是Object
,而有界类型参数的擦除是表示上限的类型。因此,如果类中的类型参数具有上限 - Holder<T extends Number>
,则T
的删除将为Number
。这意味着编译器将T
替换为Number
。
因此,在这种情况下,由于T
处于无界状态,因此其擦除为Object
。因此,编译器将其替换为Object
。
即使转换删除了编译器错误,编译器仍会显示Unchecked Cast的警告。因为,如果您使用ClassCastException
类型参数实例化泛型类型,则强制转换不是类型安全的,并且在运行时会因String
而失败。
试试这个:
Holder<String> stringHolder = new Holder<>(5);
String[] contents = stringHolder.getContents(); // ClassCastException
创建通用数组的更安全的方法是使用Array.newInstance
方法。您需要将Class<T>
参数传递给构造函数,然后使用以下代码:
public Holder(int size, Class<T> clazz){
contents = (T[]) Array.newInstance(clazz, size);
}
在这里,您还会看到Unchecked Cast
警告。但那是无害的。
更安全的方法是创建一个组件类型为类型参数的数组。您可以改为使用ArrayList<T>
。
<强>参考:强>
答案 1 :(得分:1)
T只是一个占位符。当编译错误存在时,您无法实例化它。在编译时,您需要告诉编译器占位符呈现的内容。在代码摘录的情况下,占位符就是任何东西。
答案 2 :(得分:1)
演员表出现摆脱 编译错误。它是一种未经检查的创建通用数组的方式。
即使ArrayList
遵循相同的方法。您可以查看this answer以查看已检查和未检查的方法
答案 3 :(得分:0)
如果您认为在类型擦除之后所有类型参数最终都是简单的Object
,那么您的问题就是整个Java泛型的使用。在我看来,这些是:
不幸的是,很难让Generics在Java中保持完全向后兼容性和其他目标。结果是new T[size]
无效。唯一的选择是new Object[size]
。强制转换(T[])
是告诉编译器和其他开发人员,这正是您的意图。特别是,编译器不会在此特定行中发出警告消息(这比全局禁用此类检查更安全)。