2010-04-19 5 views
4

Какая из лучших практик в этой ситуации? Я бы хотел, чтобы не инициализированный массив того же типа и длины, что и оригинал.Как создать новый массив AnyType []?

public static <AnyType extends Comparable<? super AnyType>> void someFunction(AnyType[] someArray) { 

    AnyType[] anotherArray = (AnyType[]) new Comparable[someArray.length]; 
    ...or... 
    AnyType[] anotherArray = (AnyType[]) new Object[someArray.length]; 

    ...some other code... 
} 

Спасибо, CB

+0

Почему это помечено знаком «beginner»? –

ответ

7
AnyType[] anotherArray = (AnyType[])java.lang.reflect.Array.newInstance(
     someArray.getClass().getComponentType(), someArray.length); 
+3

Следует отметить, что это создает массив, базовый тип которого совпадает с базовым типом входного массива. Это * не обязательно совпадает с параметром generic type, который будет выведен компилятором. –

+0

Также обратите внимание, что это верно и для ввода «someArray». Созданный «anotherArray» может хранить экземпляры «AnyType» точно так же безопасно, как «someArray». Таким образом, этот код не добавляет никаких ограничений, которых еще не было. –

5

Массивы и дженерики действительно не смешиваются, что хорошо. Это потому, что массивы - covariant, а дженерики - нет. Позвольте мне дать вам пример:

public static void main(String args[]) { 
    foo(new Float[1]); 
} 

public static void foo(Number[] n) { 
    n[0] = 3; 
} 

Этот код компилируется, но приведет к ArrayStoreException.

Таким образом, проблема, возникшая при воссоздании этого массива, заключается в том, что он может не быть массивом AnyType, но может быть подклассом AnyType. Разумеется, вы можете использовать someArray.getClass() и создать массив с отражением.

Общая тема, однако, заключается в том, что вы должны отдавать предпочтение List с по массивам, потому что List s не имеют те же проблемы. Изменение кода на:

public static void main(String args[]) { 
    foo(new ArrayList<Float>()); 
} 

public static void foo(List<Number> list) { 
    list.add(3); 
} 

И код не будет компилировать, который является гораздо лучшим результатом.

5

Хорошая ссылка, чтобы увидеть, как <T> T[] Collection.toArray(T[]) реализуется AbstractCollection:

public <T> T[] toArray(T[] a) { 
    // Estimate size of array; be prepared to see more or fewer elements 
    int size = size(); 
    T[] r = a.length >= size ? a : 
       (T[])java.lang.reflect.Array 
       .newInstance(a.getClass().getComponentType(), size); 
    //... 

Так методика использует:

  • Class<?> Class.getComponentType()

    Возвращает Class, представляющий тип компонента массива. Если этот класс не представляет класс массива, этот метод возвращает null.

  • Object Array.newInstance(Class<?> componentType, int... dimension)

    Создает новый массив с указанным типом компонента и размеров.

  • И, наконец, обычный старый (T[]) литой.

Если вы абсолютно необходимо создать «общий» массив, то эта методика прохождения instanceof T[] и с помощью отражения для создания экземпляра другой путь на примере Java Collections Framework.

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

С Эффективное Java 2-е издание: Пункт 25: Предпочитают списки массивам:

Таким образом, массивы и дженерики имеют очень разные правила типа. Массивы ковариантны и реанимированы, дженерики инвариантны и стираются. Как следствие, массивы обеспечивают безопасность типа времени выполнения, но не безопасность типа компиляции и наоборот для дженериков. Вообще говоря, массивы и дженерики плохо смешиваются. Если вы обнаружите, что их смешиваете и получаете ошибки времени и предупреждения компиляции, ваш первый импульс должен состоять в замене массивов на списки.

Вы должны прочитать весь предмет для более полного изучения предмета.

Смежные вопросы