У вас здесь две разные проблемы.
Во-первых, просто сотрите шаблоны и посмотрите на код без шаблонов (это то, к чему он стерется во время компиляции):
public static Comparable[] function(Comparable[] a)
{
Object[] m = new Object[2];
/* some work here */
return (Comparable[]) m;
}
Нельзя привести объект, чей фактический класс времени выполнения от Object[]
до Comparable[]
. Период.
Во-вторых, даже если вы переписали свой код для создания Comparable[]
вместо Object[]
public static <T extends Comparable<T>> T[] function(T[] a)
{
Comparable[] m = new Comparable[2];
/* some work here */
return (T[]) m;
}
все равно не будет работать. Он не будет генерировать ClassCastException внутри этой функции. Но он бросит его в любой код, который вызывает эту функцию. Например,
String[] foo = function(new String[0]);
сгенерирует исключение ClassCastException, поскольку при его удалении вы видите, что компилятор помещает приведение к элементу, который выходит из универсального метода:
String[] foo = (String[])function(new String[0]);
и вы не можете привести объект, чей фактический класс равен Comparable[]
к String[]
.
Когда вы спрашиваете «в чем разница» людям, которые сказали, что Array.newInstance()
- это способ создания массива класса, известного во время выполнения. Разница в том, что объект, возвращаемый Array.newInstance()
, имеет тип '' фактического времени выполнения '', равный Whatever[]
, где «Wh независимо» - это класс объекта класса, переданного ему. Неважно, что статический тип (тип значения времени компиляции) равен Object[]
; это фактический тип времени выполнения, который имеет значение.
Когда вы говорите «Другой вопрос, почему E [] e = (E []) new Object [3] работает», вы, вероятно, упускаете здесь несколько пунктов. Прежде всего, это работает, только если E объявлено как <E>
или <E extends Object>
, то есть нижняя граница E - Object. И во-вторых, это в основном ложь (это удобно в нескольких местах, например, для реализации универсальной коллекции; но вы должны понимать, почему это опасно); и формально, вы '' не должны '' быть в состоянии привести от объекта, фактический тип которого составляет от Object[]
до E[]
, когда E не является объектом. Это только «работает», потому что в рамках E, E стирается, и поэтому мы не можем проверить приведение. Но если вы попытаетесь вернуть этот объект как E[]
во внешний мир, вы получите ClassCastException таким же образом.