Java 数组类型擦除

Java 数组类型擦除,java,generics,Java,Generics,为什么以下代码可能不是类型安全的(编译器会生成警告) 类数组类型擦除{ 私有T[]元素; 公共void集合元素(列表元素){ this.elements=(T[])elements.toArray(); } } 我试图考虑代码会失败的任何情况,但到目前为止,只有我失败。原因很简单,因为List#toArray()返回一个对象[],所以这个方法不能保证它会返回T[] 现在,在实践中,这没关系,因为您总是知道它将返回想要的类型 您可以使用@SuppressWarnings(“unchecked”)

为什么以下代码可能不是类型安全的(编译器会生成警告)

类数组类型擦除{
私有T[]元素;
公共void集合元素(列表元素){
this.elements=(T[])elements.toArray();
}
}
我试图考虑代码会失败的任何情况,但到目前为止,只有我失败。

原因很简单,因为
List#toArray()
返回一个
对象[]
,所以这个方法不能保证它会返回
T[]

现在,在实践中,这没关系,因为您总是知道它将返回想要的类型

您可以使用
@SuppressWarnings(“unchecked”)
来避免出现此警告

,这仅仅是因为
列表#toArray()
返回一个
对象[]
,因此此方法不能保证它会返回
T[]

现在,在实践中,这没关系,因为您总是知道它将返回想要的类型


您可以使用
@SuppressWarnings(“unchecked”)
避免由于类型擦除而出现此警告,您可以将
List
s强制转换为
List
s

ArrayTypeErasure er=新的ArrayTypeErasure();
ArrayTypeErasure erased=er;
List intList=新列表();//编译警告,但是
增加(1);
已删除。setElements(intList);

由于类型擦除,您可以将
List
s强制转换为
List
s

ArrayTypeErasure er=新的ArrayTypeErasure();
ArrayTypeErasure erased=er;
List intList=新列表();//编译警告,但是
增加(1);
已删除。setElements(intList);

首先,请注意数组在运行时知道其组件类型,但泛型类的实例在运行时不知道泛型类型参数。
列表
无法在运行时创建运行时类型为
T[]
的数组对象,因为它不知道运行时的
T
是什么。采用一个数组参数的
List#toArray()
方法使用传入数组实例的运行时类型在运行时构造相同组件类型的数组。但是没有参数的
列表#toArray()
总是创建一个运行时类型为
对象[]
的数组。因此,
elements.toArray()
计算的数组实例的运行时类型始终为
Object[]

Object[]
不是
T[]
的子类型(当
T
不是
Object
时),因此将此数组分配给
this。编译时类型
T[]
的元素
,是错误的。但是,它不会立即导致任何异常,因为
t
的擦除是
Object
,所以
t[]
的擦除是
Object[]
,将
Object[]
分配给
Object[]
是可以的。只要您确保从不将
this.elements
中包含的对象作为
t[]
暴露到此对象之外,它就不会引起任何问题。但是,如果将
this.elements
中包含的对象作为类型
T[]
公开给类外(例如,将
this.elements
返回为类型
T[]
的方法,或者如果将
this.elements
设置为公共或受保护字段),则类外的调用方可能期望
T
为特定类型,这可能会导致类强制转换异常

例如,如果有一个方法将
this.elements
作为类型
T[]
返回:

public T[] getElements() {
    return this.elements;
}
ArrayTypeErasure<String> foo = ...
String[] bar = foo.getElements();
然后有一个调用者持有
ArrayTypeErasure
,它调用
.getElements()
,它需要一个
字符串[]
。当它尝试将结果分配给
字符串[]
时,将导致类强制转换异常,因为对象的运行时类型是
对象[]

public T[] getElements() {
    return this.elements;
}
ArrayTypeErasure<String> foo = ...
String[] bar = foo.getElements();
ArrayTypeErasure foo=。。。
字符串[]bar=foo.getElements();

首先,请注意数组在运行时知道其组件类型,但泛型类的实例在运行时不知道泛型类型参数。
列表
无法在运行时创建运行时类型为
T[]
的数组对象,因为它不知道运行时的
T
是什么。采用一个数组参数的
List#toArray()
方法使用传入数组实例的运行时类型在运行时构造相同组件类型的数组。但是没有参数的
列表#toArray()
总是创建一个运行时类型为
对象[]
的数组。因此,
elements.toArray()
计算的数组实例的运行时类型始终为
Object[]

Object[]
不是
T[]
的子类型(当
T
不是
Object
时),因此将此数组分配给
this。编译时类型
T[]
的元素
,是错误的。但是,它不会立即导致任何异常,因为
t
的擦除是
Object
,所以
t[]
的擦除是
Object[]
,将
Object[]
分配给
Object[]
是可以的。只要您确保从不将
this.elements
中包含的对象作为
t[]
暴露到此对象之外,它就不会引起任何问题。但是,如果将
this.elements
中包含的对象作为类型
T[]
公开给类外(例如,将
this.elements
返回为类型
T[]
的方法,或者如果将
this.elements
设置为公共或受保护字段),则类外的调用方可能期望
T
为特定类型,这可能会导致类强制转换异常

例如,如果有一个方法将
this.elements
作为类型
T[]
返回:

public T[] getElements() {
    return this.elements;
}
ArrayTypeErasure<String> foo = ...
String[] bar = foo.getElements();
然后有一个调用者持有
ArrayTypeErasure
,它调用
.getElements()
,它需要一个
字符串[