привести объект к Comparable в Java

Здесь у нас есть общий метод:

public static <T extends Comparable<T>> T[] function(T[] a)
{
    Object[] m = new Object[2];

    /* some work here */

    return (T[]) m;
}

Выбрасывается ClassCastException. Что с этим не так?


person Majid Azimi    schedule 30.06.2011    source источник
comment
Какова точная трассировка стека? Также опубликуйте код, который вызывает исключение.   -  person Buhake Sindi    schedule 30.06.2011
comment
Вы используете Java Generics в C# Generics Way.   -  person schlingel    schedule 30.06.2011
comment
@Elite - я искренне сомневаюсь, что есть трассировка стека или исключение, потому что код не скомпилируется.   -  person Ted Hopp    schedule 30.06.2011


Ответы (6)


У вас здесь две разные проблемы.

Во-первых, просто сотрите дженерики и посмотрите на код без дженериков (это то, к чему он стирается во время компиляции):

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.

person newacct    schedule 01.07.2011

Массив Object не является массивом какого-либо подкласса Object. Вы столкнулись с одним из ограничений дженериков в Java: вы не можете создать универсальный массив. См. эту тему, чтобы узнать о действительно работающем подходе.

person Ted Hopp    schedule 30.06.2011
comment
Но мы можем написать такой код: E[] array = (E[]) new Object[10]; //Although is gives warning Он такой же, как в коде, не так ли? - person Majid Azimi; 30.06.2011
comment
Если вы скомпилируете это с помощью -Xlint:unchecked, вы получите предупреждение. И вы не будете довольны результатами во время выполнения, если только E не будет Object. - person Ted Hopp; 30.06.2011

Object не Comparable. Вы должны определить свой массив как сопоставимый тип.

Поскольку вы передаете массив, вы можете использовать тип массива:

T[] m = Array.newInstance(a.getClass().getComponentType(), 2);

И, конечно же, вам нужно будет поместить внутрь Comparable объекта.

person Bozho    schedule 30.06.2011
comment
Так что же такое почтение? Array.newInstance создает новый массив и возвращает Object[], затем мы приводим его к T[]. Это то, что я сделал в коде. - person Majid Azimi; 30.06.2011
comment
Важной частью является размещение сопоставимых объектов внутри массива. newInstance просто сохраняет некоторое приведение. - person Bozho; 01.07.2011
comment
@Majid Array.newInstance, используемый здесь, создаст новый массив того же класса, что и ввод. В Java есть разница между массивами с разными типами компонентов, Object[] и Comparable[] — это два разных класса. В этом легко убедиться, если сравнить результат getClass на двух массивах разных типов. Поскольку Object не того же типа, что и ваш общий T (и никогда не может быть), вы всегда будете получать ClassCastException. - person Andreas Holstenson; 01.07.2011
comment
Объект является суперклассом всех классов. почему мы не можем назначать ему массивы разных классов? Другой вопрос, почему 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.

person Luciano    schedule 30.06.2011

T extends Comparable означает, что параметр метода (в данном случае T) должен расширяться от сопоставимого. Поэтому, когда вы пытаетесь сделать следующее приведение

(T[]) m;

Вы пытаетесь привести Object[] к Comparable[] (или к чему-либо, что расширяет Comparable).

person Alfredo Osorio    schedule 30.06.2011

Это то, что вы хотите делать:

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;
}
person Reverend Gonzo    schedule 30.06.2011