приведение объекта к сопоставимым в Java - PullRequest
4 голосов
/ 30 июня 2011

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

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

    /* some work here */

    return (T[]) m;
}

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

Ответы [ 6 ]

4 голосов
/ 30 июня 2011

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

3 голосов
/ 01 июля 2011

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

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

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 таким же образом.

3 голосов
/ 30 июня 2011

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

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

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

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

2 голосов
/ 30 июня 2011

Ну, на самом деле вы не можете привести массив объектов к массиву Comparables. Это не имеет никакого смысла. Почему компилятор позволил это? Более того, например, класс Integer реализует Comparable, но вы не можете привести массив Comparable к массиву Integer.

0 голосов
/ 30 июня 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;
}
0 голосов
/ 30 июня 2011

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

(T[]) m;

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

...