Никто другой не ответил на вопрос о том, что происходит в приведенном вами примере.
import java.lang.reflect.Array;
class Stack<T> {
public Stack(Class<T> clazz, int capacity) {
array = (T[])Array.newInstance(clazz, capacity);
}
private final T[] array;
}
Как уже говорили другие, дженерики "стираются" во время компиляции. Таким образом, во время выполнения экземпляр универсального не знает, каков его тип компонента. Причина этого историческая: Sun хотела добавить универсальные шаблоны, не нарушая существующий интерфейс (как исходный, так и двоичный).
С другой стороны, массивы do знают тип своего компонента во время выполнения.
Этот пример обходит проблему, заставляя код, вызывающий конструктор (который знает тип), передавать параметр, сообщающий классу требуемый тип.
Таким образом, приложение будет конструировать класс с чем-то вроде
Stack<foo> = new Stack<foo>(foo.class,50)
и конструктор теперь знает (во время выполнения), что представляет собой тип компонента, и может использовать эту информацию для создания массива с помощью API отражения.
Array.newInstance(clazz, capacity);
Наконец, у нас есть приведение типа, потому что компилятор не может знать, что массив, возвращаемый Array#newInstance()
, является правильным типом (даже если мы знаем).
Этот стиль немного уродлив, но иногда он может быть наименее плохим решением для создания универсальных типов, которым необходимо знать их тип компонента во время выполнения по любой причине (создание массивов или создание экземпляров их типа компонентов и т. Д.) .