2015-06-02 3 views
1

У меня есть класс контейнера, который выглядит следующим образом. (Я удаляю все методы логики, чтобы не загромождать)Java generics, отличая T [] до исходного типа

public abstract class Container<T> { 

    protected T[] array; 

    public Container(int capacity) { 
     array = (T[]) new Object[capacity]; 
    } 

    public T[] array() { 
     return array; 
    } 
} 

Этот класс используется, например, так:

public final class ItemContainer extends Container<Item> { 

    public ItemContainer(int capacity) { 
     super(capacity); 
    } 

} 

Этот контейнер теперь должен держать массив элементов. Однако при попытке передать его в Item[] будет использоваться, представлена ​​следующая ошибка:

Исключение в потоке «ForkJoinPool-2-рабоче-1» java.lang.ClassCastException: [Ljava.lang.Object ; не может быть добавлено к [Lcom.oblivion.entity.item.Item;

Как я могу обойти это?

+0

Есть причина, почему вы используете массив вместо некоторой коллекции (Set, List, ...)? Те из вас могли бы сделать то, что вам нужно, чище. – LionC

+0

@LionC. Задача для этого проекта заключалась в том, чтобы не использовать библиотеку Collections. Я мог бы легко выполнить эту функцию, используя «Список <>' Примечание: не школьный проект, а только личный. – Hobbyist

+0

«Задача» в том смысле, что вы не можете использовать ее по техническим причинам или для вызова в том смысле, что хотите попробовать использовать Java без коллекций? – LionC

ответ

1

Когда вы создаете массив объекта (или любого другого объекта на самом деле), он не меняет типы, когда вы бросаете, на самом деле кастинг на общий T [] не имеет никакого эффекта. Поэтому метод array возвращает массив объекта, который вызывающий пытается сделать неявным для массива Item, и это, конечно, терпит неудачу.

Если вы хотите создать массив параметрического типа, у вас должен быть метод, который принимает Class<T>. Затем вы можете создать массив, используя метод Array.newInstance.

В качестве альтернативы вы можете использовать подход, используемый ArrayList: использовать массив объекта внутри и потребовать, чтобы вызывающий передал массив соответствующего типа, если ему нужен снимок данных.

1
public Container(Class<T> clazz, int capacity) { 
    array = (T[]) Array.newInstance(clazz, capacity); 
} 

Потребность в актерском составе - это небольшая ошибка в оформлении языка. Существует перегруженный newInstance с несколькими измерениями, поэтому в случае T[]...[] общий тип результата невозможен.

Вы можете сохранить класс компонента для создания объекта или бросает:

T t = clazz.cast(object); 
T t = clazz.newInstance(); 
Смежные вопросы