Во-первых, обратите внимание, что массивы знают свой тип компонента во время выполнения, но экземпляры универсальных классов не знают аргумента универсального типа во время выполнения.List<T>
не может создать объект массива во время выполнения с типом времени выполнения T[]
без дополнительной информации, поскольку он не знает, что такое T
во время выполнения.Метод List#toArray()
, который принимает один параметр массива, использует тип времени выполнения переданного экземпляра массива для создания массива того же типа компонента во время выполнения.Но List#toArray()
без параметров всегда создает массив с типом времени выполнения Object[]
.Таким образом, elements.toArray()
оценивает экземпляр массива, который всегда имеет тип времени выполнения Object[]
.
Object[]
не является подтипом T[]
(когда T
не Object
), поэтомуприсвоение этого массива this.elements
типа компиляции 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>
, и она вызывает .getElements()
, она будет ожидать String[]
.Когда он пытается присвоить результат String[]
, это вызовет исключение приведения класса, поскольку тип времени выполнения объекта - Object[]
:
ArrayTypeErasure<String> foo = ...
String[] bar = foo.getElements();