Здесь у нас есть общий метод:
public static <T extends Comparable<T>> T[] function(T[] a)
{
Object[] m = new Object[2];
/* some work here */
return (T[]) m;
}
Выбрасывается ClassCastException
. Что с этим не так?
Здесь у нас есть общий метод:
public static <T extends Comparable<T>> T[] function(T[] a)
{
Object[] m = new Object[2];
/* some work here */
return (T[]) m;
}
Выбрасывается ClassCastException
. Что с этим не так?
У вас здесь две разные проблемы.
Во-первых, просто сотрите дженерики и посмотрите на код без дженериков (это то, к чему он стирается во время компиляции):
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[]
, где «независимо» — это класс переданного ему объекта класса. Неважно, что статический тип (тип значения времени компиляции) — Object[]
; это фактический тип времени выполнения, который имеет значение.
Когда вы говорите: «Другой вопрос, почему E[] e = (E[]) new Object[3] работает», вы, вероятно, упускаете здесь несколько моментов. Прежде всего, это работает только в том случае, если E объявлен как <E>
или <E extends Object>
, т. е. нижняя граница E — это Object. И, во-вторых, это в основном ложь (это удобно в нескольких местах, например, реализация универсальной коллекции, но вы должны понимать, почему это опасно); и формально вы «не должны» иметь возможность приведения от объекта, фактический тип которого Object[]
, к E[]
, когда E не является Object. Это «работает» только потому, что в рамках E E стирается, и поэтому мы не можем проверить приведение. Но если вы попытаетесь вернуть этот объект как E[]
во внешний мир, вы точно так же получите ClassCastException.
Массив Object не является массивом какого-либо подкласса Object. Вы столкнулись с одним из ограничений дженериков в Java: вы не можете создать универсальный массив. См. эту тему, чтобы узнать о действительно работающем подходе.
E[] array = (E[]) new Object[10]; //Although is gives warning
Он такой же, как в коде, не так ли?
- person Majid Azimi; 30.06.2011
-Xlint:unchecked
, вы получите предупреждение. И вы не будете довольны результатами во время выполнения, если только E
не будет Object
.
- person Ted Hopp; 30.06.2011
Object
не Comparable
. Вы должны определить свой массив как сопоставимый тип.
Поскольку вы передаете массив, вы можете использовать тип массива:
T[] m = Array.newInstance(a.getClass().getComponentType(), 2);
И, конечно же, вам нужно будет поместить внутрь Comparable
объекта.
Array.newInstance
создает новый массив и возвращает Object[]
, затем мы приводим его к T[]
. Это то, что я сделал в коде.
- person Majid Azimi; 30.06.2011
E[] e = (E[]) new Object[3]
работает, а Object[] o = new Object[3]
и потом E[] e = (E[]) o
не работает? Они делают то же самое? не так ли?
- person Majid Azimi; 01.07.2011
Ну, на самом деле вы не можете преобразовать массив объектов в массив Comparables. Это не имеет никакого смысла. Почему компилятор это допускает? Более того, например, класс Integer реализует Comparable, но вы не можете преобразовать массив Comparable в массив Integer.
T extends Comparable означает, что параметр метода (в данном случае T) должен расширяться от сопоставимого. Поэтому, когда вы пытаетесь сделать следующее приведение
(T[]) m;
Вы пытаетесь привести Object[] к Comparable[] (или к чему-либо, что расширяет Comparable).
Это то, что вы хотите делать:
public static <T extends Comparable<T>> T[] function(final T[] a) {
final T[] m = (T[]) Array.newInstance(a.getClass().getComponentType(), 2);
/* some work here */
return m;
}